From 64b917c1a36e07dc184d1d5db0bd9c944b8cca19 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 26 May 2020 13:33:49 +0300 Subject: [PATCH 001/492] Split code into sub-modules and define webhook-receiver module --- .gitignore | 2 + build.gradle | 139 ++++++++++-------- google-chat-bot/build.gradle | 5 + .../java/io/spine/chatbot/Application.java | 0 .../io/spine/chatbot/HelloController.java | 0 .../src}/main/resources/application.yml | 0 .../src}/main/resources/log4j2.xml | 0 .../io/spine/chatbot/HelloFunctionTest.java | 0 gradle.properties | 1 + settings.gradle | 3 + src/test/java/io.spine/.gitkeep | 0 webhook-receiver/build.gradle | 5 + .../github/webhook/receiver/Application.java | 10 ++ .../github/webhook/receiver/Receiver.java | 13 ++ .../src/main/resources/application.yml | 3 + .../src/main/resources/log4j2.xml | 16 ++ .../github/webhook/receiver/ReceiverTest.java | 44 ++++++ 17 files changed, 177 insertions(+), 64 deletions(-) create mode 100644 google-chat-bot/build.gradle rename {src => google-chat-bot/src}/main/java/io/spine/chatbot/Application.java (100%) rename {src => google-chat-bot/src}/main/java/io/spine/chatbot/HelloController.java (100%) rename {src => google-chat-bot/src}/main/resources/application.yml (100%) rename {src => google-chat-bot/src}/main/resources/log4j2.xml (100%) rename {src => google-chat-bot/src}/test/java/io/spine/chatbot/HelloFunctionTest.java (100%) delete mode 100644 src/test/java/io.spine/.gitkeep create mode 100644 webhook-receiver/build.gradle create mode 100644 webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java create mode 100644 webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java create mode 100644 webhook-receiver/src/main/resources/application.yml create mode 100644 webhook-receiver/src/main/resources/log4j2.xml create mode 100644 webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java diff --git a/.gitignore b/.gitignore index 983275cd..6d9e68c9 100644 --- a/.gitignore +++ b/.gitignore @@ -219,3 +219,5 @@ gradle-app.setting # .nfs files are created when an open file is removed but is still being accessed .nfs* +# Local gradle properties that overrides default gradle.properties and are private +gradle-local.properties diff --git a/build.gradle b/build.gradle index b839bdfb..07b34343 100644 --- a/build.gradle +++ b/build.gradle @@ -1,83 +1,94 @@ -plugins { - id "net.ltgt.apt-eclipse" version "0.21" - id "com.github.johnrengelman.shadow" version "5.2.0" - id "application" - id "com.google.cloud.tools.jib" version "2.3.0" -} - -version "0.1" -group "io.spine" - +buildscript { + repositories { + gradlePluginPortal() + jcenter() + mavenCentral() + } -repositories { - jcenter() - mavenCentral() + dependencies { + classpath "net.ltgt.gradle:gradle-apt-plugin:0.21" + classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" + classpath "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.3.0" + classpath "net.saliman:gradle-properties-plugin:1.5.1" + } } -configurations { - // for dependencies that are needed for development only - developmentOnly - invoker +allprojects { + version "0.1" + group "io.spine" + apply plugin: "idea" + apply plugin: "net.saliman.properties" } -dependencies { - annotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - annotationProcessor("io.micronaut:micronaut-inject-java") - annotationProcessor("io.micronaut:micronaut-validation") +subprojects { + apply plugin: "net.ltgt.apt-idea" + apply plugin: "com.github.johnrengelman.shadow" + apply plugin: "application" + apply plugin: "com.google.cloud.tools.jib" - compileOnly(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) + repositories { + jcenter() + mavenCentral() + } + configurations { + // for dependencies that are needed for development only + developmentOnly + invoker + } - implementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - implementation("io.micronaut:micronaut-inject") - implementation("io.micronaut:micronaut-validation") - implementation("io.micronaut:micronaut-runtime") + dependencies { + annotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) + annotationProcessor("io.micronaut:micronaut-inject-java") + annotationProcessor("io.micronaut:micronaut-validation") - implementation "io.micronaut:micronaut-http-server-netty" - implementation("javax.annotation:javax.annotation-api") + compileOnly(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - implementation("org.apache.logging.log4j:log4j-core:2.13.3") - runtimeOnly("org.apache.logging.log4j:log4j-api:2.13.3") - runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.3") + implementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) + implementation("io.micronaut:micronaut-inject") + implementation("io.micronaut:micronaut-validation") + implementation("io.micronaut:micronaut-runtime") - testAnnotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - testAnnotationProcessor("io.micronaut:micronaut-inject-java") - testImplementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - testImplementation("io.micronaut:micronaut-http-client") - testImplementation("org.junit.jupiter:junit-jupiter-api") - testImplementation("io.micronaut.test:micronaut-test-junit5") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") -} + implementation "io.micronaut:micronaut-http-server-netty" + implementation("javax.annotation:javax.annotation-api") -test.classpath += configurations.developmentOnly + implementation("org.apache.logging.log4j:log4j-core:2.13.3") + runtimeOnly("org.apache.logging.log4j:log4j-api:2.13.3") + runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.3") -mainClassName = "io.spine.chatbot.Application" + testAnnotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) + testAnnotationProcessor("io.micronaut:micronaut-inject-java") + testImplementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) + testImplementation("io.micronaut:micronaut-http-client") + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("io.micronaut.test:micronaut-test-junit5") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + } -test { - useJUnitPlatform() -} + test.classpath += configurations.developmentOnly -java { - sourceCompatibility = JavaVersion.toVersion('11') - targetCompatibility = JavaVersion.toVersion('11') -} + mainClassName = "io.spine.chatbot.Application" -tasks.withType(JavaCompile) { - options.encoding = "UTF-8" - options.compilerArgs.add('-parameters') -} + test { + useJUnitPlatform() + } -tasks.withType(JavaExec) { - classpath += configurations.developmentOnly - jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote') -} + java { + sourceCompatibility = JavaVersion.toVersion('11') + targetCompatibility = JavaVersion.toVersion('11') + } -shadowJar { - minimize() - mergeServiceFiles() -} + tasks.withType(JavaCompile) { + options.encoding = "UTF-8" + options.compilerArgs.add('-parameters') + } -jib { - to { - image = 'gcr.io/chat-bot/jib-image' + tasks.withType(JavaExec) { + classpath += configurations.developmentOnly + jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote') } -} + + shadowJar { + minimize() + mergeServiceFiles() + } +} \ No newline at end of file diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle new file mode 100644 index 00000000..6566209f --- /dev/null +++ b/google-chat-bot/build.gradle @@ -0,0 +1,5 @@ +jib { + to { + image = "gcr.io/${gcpProject}/chat-bot" + } +} diff --git a/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java similarity index 100% rename from src/main/java/io/spine/chatbot/Application.java rename to google-chat-bot/src/main/java/io/spine/chatbot/Application.java diff --git a/src/main/java/io/spine/chatbot/HelloController.java b/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java similarity index 100% rename from src/main/java/io/spine/chatbot/HelloController.java rename to google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java diff --git a/src/main/resources/application.yml b/google-chat-bot/src/main/resources/application.yml similarity index 100% rename from src/main/resources/application.yml rename to google-chat-bot/src/main/resources/application.yml diff --git a/src/main/resources/log4j2.xml b/google-chat-bot/src/main/resources/log4j2.xml similarity index 100% rename from src/main/resources/log4j2.xml rename to google-chat-bot/src/main/resources/log4j2.xml diff --git a/src/test/java/io/spine/chatbot/HelloFunctionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java similarity index 100% rename from src/test/java/io/spine/chatbot/HelloFunctionTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java diff --git a/gradle.properties b/gradle.properties index 988b791e..c13712a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ micronautVersion=2.0.0.M3 +gcpProject='' \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 61ffebc0..75a94415 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,4 @@ rootProject.name="chat-bot" +include 'webhook-receiver' +include 'google-chat-bot' + diff --git a/src/test/java/io.spine/.gitkeep b/src/test/java/io.spine/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/webhook-receiver/build.gradle b/webhook-receiver/build.gradle new file mode 100644 index 00000000..c3e7dc5a --- /dev/null +++ b/webhook-receiver/build.gradle @@ -0,0 +1,5 @@ +jib { + to { + image = "gcr.io/${gcpProject}/github-webhook-receiver" + } +} diff --git a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java new file mode 100644 index 00000000..ce8bfc52 --- /dev/null +++ b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java @@ -0,0 +1,10 @@ +package io.spine.github.webhook.receiver; + +import io.micronaut.runtime.Micronaut; + +public class Application { + + public static void main(String[] args) { + Micronaut.run(Application.class, args); + } +} diff --git a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java new file mode 100644 index 00000000..3ca1fba5 --- /dev/null +++ b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java @@ -0,0 +1,13 @@ +package io.spine.github.webhook.receiver; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; + +@Controller("/web-hook") +public class Receiver { + + @Get(uri="/", produces="text/plain") + public String process() { + return "OK"; + } +} \ No newline at end of file diff --git a/webhook-receiver/src/main/resources/application.yml b/webhook-receiver/src/main/resources/application.yml new file mode 100644 index 00000000..544b180f --- /dev/null +++ b/webhook-receiver/src/main/resources/application.yml @@ -0,0 +1,3 @@ +micronaut: + application: + name: webhookReceiver diff --git a/webhook-receiver/src/main/resources/log4j2.xml b/webhook-receiver/src/main/resources/log4j2.xml new file mode 100644 index 00000000..91520d6f --- /dev/null +++ b/webhook-receiver/src/main/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java b/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java new file mode 100644 index 00000000..db416f21 --- /dev/null +++ b/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java @@ -0,0 +1,44 @@ +package io.spine.github.webhook.receiver; + +import io.micronaut.context.ApplicationContext; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.client.HttpClient; +import io.micronaut.runtime.server.EmbeddedServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@DisplayName("Receiver should") +final class ReceiverTest { + + + private static EmbeddedServer server; + private static HttpClient client; + + @BeforeAll + public static void setupServer() { + server = ApplicationContext.run(EmbeddedServer.class); + client = server + .getApplicationContext() + .createBean(HttpClient.class, server.getURL()); + } + + @AfterAll + public static void stopServer() { + if (server != null) { + server.stop(); + } + if (client != null) { + client.stop(); + } + } + + @Test + void processIncomingWebHook() { + String actual = client.toBlocking().retrieve(HttpRequest.GET("/web-hook")); + assertEquals("OK", actual); + } +} From e29fac2cef77fc8e6ead29dd42708d8b5f087b8f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 26 May 2020 14:38:47 +0300 Subject: [PATCH 002/492] Downgrade gradle version to v6.3 See https://github.com/SpineEventEngine/bootstrap/issues/49 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9ecfb344..42176947 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ -#Mon May 25 21:30:17 EEST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip +#Tue May 26 14:15:06 EEST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From 9216ad1f40b5a5eeb2b8e84efa64bf74b22722fc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 26 May 2020 14:40:57 +0300 Subject: [PATCH 003/492] Use `plugins` section instead of `buildscript` --- build.gradle | 23 ++++++++++------------- google-chat-bot/build.gradle | 13 +++++++++++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 07b34343..8496eeb4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,10 @@ -buildscript { - repositories { - gradlePluginPortal() - jcenter() - mavenCentral() - } - - dependencies { - classpath "net.ltgt.gradle:gradle-apt-plugin:0.21" - classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" - classpath "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.3.0" - classpath "net.saliman:gradle-properties-plugin:1.5.1" - } +plugins { + id "net.ltgt.apt" version "0.21" apply false + id "com.github.johnrengelman.shadow" version "5.2.0" apply false + id 'com.google.cloud.tools.jib' version '2.3.0' apply false + id "net.saliman.properties" version "1.5.1" apply false + id 'io.spine.tools.gradle.bootstrap' version '1.5.8' apply false + id "net.ltgt.errorprone" version "1.1.1" apply false } allprojects { @@ -25,6 +19,7 @@ subprojects { apply plugin: "com.github.johnrengelman.shadow" apply plugin: "application" apply plugin: "com.google.cloud.tools.jib" + apply plugin: "net.ltgt.errorprone" repositories { jcenter() @@ -37,6 +32,7 @@ subprojects { } dependencies { + errorprone "com.google.errorprone:error_prone_core:2.3.4" annotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) annotationProcessor("io.micronaut:micronaut-inject-java") annotationProcessor("io.micronaut:micronaut-validation") @@ -47,6 +43,7 @@ subprojects { implementation("io.micronaut:micronaut-inject") implementation("io.micronaut:micronaut-validation") implementation("io.micronaut:micronaut-runtime") + implementation("com.google.guava:guava:29.0-jre") implementation "io.micronaut:micronaut-http-server-netty" implementation("javax.annotation:javax.annotation-api") diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 6566209f..3937dfc4 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -1,3 +1,16 @@ +apply plugin: 'io.spine.tools.gradle.bootstrap' + +spine { + enableJava().server() + modelCompiler { + generateValidation = true + } +} + +dependencies { + testImplementation "io.spine:spine-testutil-server:${spine.version()}" +} + jib { to { image = "gcr.io/${gcpProject}/chat-bot" From 9f5251a1376a67586fc38c272ea6713468db7639 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 27 May 2020 20:58:15 +0300 Subject: [PATCH 004/492] Add initial protos --- .gitignore | 2 ++ .../spine/chatbot/github/identifiers.proto | 25 ++++++++++++++ .../spine/chatbot/github/organization.proto | 33 +++++++++++++++++++ .../github/organization_commands.proto | 31 +++++++++++++++++ .../chatbot/github/organization_events.proto | 31 +++++++++++++++++ .../spine/chatbot/github/repository.proto | 30 +++++++++++++++++ .../chatbot/github/repository_commands.proto | 29 ++++++++++++++++ .../chatbot/github/repository_events.proto | 29 ++++++++++++++++ 8 files changed, 210 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto diff --git a/.gitignore b/.gitignore index 6d9e68c9..8500a032 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,5 @@ gradle-app.setting # Local gradle properties that overrides default gradle.properties and are private gradle-local.properties + +**/generated/** diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto new file mode 100644 index 00000000..a3f89e6a --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github"; +option java_outer_classname = "IdentifiersProto"; +option java_multiple_files = true; + +import "spine/time/time.proto"; +import "spine/core/user_id.proto"; + +// Internal GitHub organization ID. +message OrganizationId { + + string uuid = 1[(required) = true]; +} + +// Internal GitHub repository ID. +message RepositoryId { + + string uuid = 1[(required) = true]; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto new file mode 100644 index 00000000..539644c2 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.organization"; +option java_outer_classname = "OrganizationProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +// A GitHub organization. +message Organization { + option (entity).kind = AGGREGATE; + + OrganizationId id = 1; + + // Name of the GitHub organization. + string name = 2; + + // URL of the official organization-related website. + spine.net.Url website_url = 3; + + // URL of the organization GitHub profile. + spine.net.Url github_url = 4; + + // URL of the organization Travis CI profile. + spine.net.Url travis_ci_url = 5; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto new file mode 100644 index 00000000..e2826a27 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.organization.command"; +option java_outer_classname = "OrganizationCommandsProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +message RegisterOrganization { + + OrganizationId id = 1 [(required) = true]; + + // Name of the GitHub organization. + string name = 2 [(required) = true]; + + // URL of the official organization-related website. + spine.net.Url website_url = 3; + + // URL of the organization GitHub profile. + spine.net.Url github_url = 4 [(required) = true]; + + // URL of the organization Travis CI profile. + spine.net.Url travis_ci_url = 5 [(required) = true]; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto new file mode 100644 index 00000000..8084b272 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.organization.event"; +option java_outer_classname = "OrganizationEventsProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +message OrganizationRegistered { + + OrganizationId id = 1 [(required) = true]; + + // Name of the GitHub organization. + string name = 2 [(required) = true]; + + // URL of the official organization-related website. + spine.net.Url website_url = 3; + + // URL of the organization GitHub profile. + spine.net.Url github_url = 4 [(required) = true]; + + // URL of the organization Travis CI profile. + spine.net.Url travis_ci_url = 5 [(required) = true]; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto new file mode 100644 index 00000000..b4d404a2 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github"; +option java_outer_classname = "GithubOrganizationProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +// A GitHub repository. +message Repository { + option (entity).kind = AGGREGATE; + + RepositoryId id = 1; + + // Name of the repository. + string name = 2; + + // GitHub URL of the repository. + spine.net.Url github_url = 3; + + // Travis CI URL of the repository. + spine.net.Url travis_ci_url = 4; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto new file mode 100644 index 00000000..9ff84646 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.repository.command"; +option java_outer_classname = "RepositoryCommandsProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +// Registers a new repository in the system. +message RegisterRepository { + + RepositoryId id = 1 [(required) = true]; + + // Name of the repository. + string name = 2 [(required) = true]; + + // GitHub URL of the repository. + spine.net.Url github_url = 3 [(required) = true]; + + // Travis CI URL of the repository. + spine.net.Url travis_ci_url = 4 [(required) = true]; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto new file mode 100644 index 00000000..8da2a30e --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.repository.event"; +option java_outer_classname = "RepositoryEventsProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +// Denotes that a new repository is registered. +message RepositoryRegistered { + + RepositoryId id = 1 [(required) = true]; + + // Name of the repository. + string name = 2 [(required) = true]; + + // GitHub URL of the repository. + spine.net.Url github_url = 3 [(required) = true]; + + // Travis CI URL of the repository. + spine.net.Url travis_ci_url = 4 [(required) = true]; +} From 89ff06a987f222d100eda5e0797439b01bdeddfa Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 28 May 2020 19:53:14 +0300 Subject: [PATCH 005/492] Add IDEA configs --- .idea/codeStyleSettings.xml | 52 ++ .idea/codeStyles/Project.xml | 75 ++ .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/copyright/TeamDev_Open_Source.xml | 6 + .idea/copyright/profiles_settings.xml | 7 + .idea/dictionaries/common.xml | 65 ++ .idea/filetypes/Google Protobuf.xml | 18 + .idea/inspectionProfiles/Project_Default.xml | 878 +++++++++++++++++++ .idea/vcs.xml | 6 + 9 files changed, 1112 insertions(+) create mode 100644 .idea/codeStyleSettings.xml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/copyright/TeamDev_Open_Source.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/dictionaries/common.xml create mode 100644 .idea/filetypes/Google Protobuf.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 00000000..123c5876 --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,52 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..d1143f76 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,75 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/TeamDev_Open_Source.xml b/.idea/copyright/TeamDev_Open_Source.xml new file mode 100644 index 00000000..10ab8291 --- /dev/null +++ b/.idea/copyright/TeamDev_Open_Source.xml @@ -0,0 +1,6 @@ + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..0b8f9a19 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/dictionaries/common.xml b/.idea/dictionaries/common.xml new file mode 100644 index 00000000..c6d06b80 --- /dev/null +++ b/.idea/dictionaries/common.xml @@ -0,0 +1,65 @@ + + + + afghani + arraybuffer + aspx + bytebuffer + closeables + cqrs + dartdocs + dataset + datastore + datastores + deserialized + dirham + enrichable + enrichments + escaper + flushables + googleapis + gradle + grpc + handshaker + hohpe + idempotency + lempira + liskov + melnik + memoized + memoizes + memoizing + mergeable + mikhaylov + millisecs + multitenancy + multitenant + nullable + onclose + oneof + onmessage + onopen + parameterizing + plugable + processmanager + procman + proto's + protos + sfixed + stderr + stringifier + stringifiers + switchman + testutil + threeten + tuples + unregister + unregistering + unregisters + unregistration + websocket + workflows + yevsyukov + + + diff --git a/.idea/filetypes/Google Protobuf.xml b/.idea/filetypes/Google Protobuf.xml new file mode 100644 index 00000000..270fe82c --- /dev/null +++ b/.idea/filetypes/Google Protobuf.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..03926c8c --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,878 @@ + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 5c55d5369ca15ce9e4bdbfb04eaec857e4683e17 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 28 May 2020 19:54:19 +0300 Subject: [PATCH 006/492] Cleanup code --- .../io/spine/chatbot/HelloController.java | 25 +++++++++++++++++-- .../spine/chatbot/github/identifiers.proto | 4 +-- .../io/spine/chatbot/HelloFunctionTest.java | 23 ++++++++++++++++- settings.gradle | 22 +++++++++++++++- .../github/webhook/receiver/Receiver.java | 22 +++++++++++++++- .../github/webhook/receiver/ReceiverTest.java | 24 ++++++++++++++++-- 6 files changed, 111 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java b/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java index e41de7bf..280bd588 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java @@ -1,11 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot; -import io.micronaut.http.annotation.*; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; @Controller("/hello") public class HelloController { - @Get(uri="/", produces="text/plain") + @Get(uri = "/", produces = "text/plain") public String index() { return "Example Response"; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index a3f89e6a..9c5189b2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -15,11 +15,11 @@ import "spine/core/user_id.proto"; // Internal GitHub organization ID. message OrganizationId { - string uuid = 1[(required) = true]; + string uuid = 1 [(required) = true]; } // Internal GitHub repository ID. message RepositoryId { - string uuid = 1[(required) = true]; + string uuid = 1 [(required) = true]; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java index 39a16676..be98687f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot; import io.micronaut.context.ApplicationContext; @@ -37,7 +57,8 @@ public static void stopServer() { @Test public void testFunction() { - String actual = client.toBlocking().retrieve(HttpRequest.GET("/hello")); + String actual = client.toBlocking() + .retrieve(HttpRequest.GET("/hello")); assertEquals("Example Response", actual); } } diff --git a/settings.gradle b/settings.gradle index 75a94415..879fc013 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,24 @@ -rootProject.name="chat-bot" +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +rootProject.name = "chat-bot" include 'webhook-receiver' include 'google-chat-bot' diff --git a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java index 3ca1fba5..a48d515e 100644 --- a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java +++ b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.github.webhook.receiver; import io.micronaut.http.annotation.Controller; @@ -6,7 +26,7 @@ @Controller("/web-hook") public class Receiver { - @Get(uri="/", produces="text/plain") + @Get(uri = "/", produces = "text/plain") public String process() { return "OK"; } diff --git a/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java b/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java index db416f21..ef75dde9 100644 --- a/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java +++ b/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.github.webhook.receiver; import io.micronaut.context.ApplicationContext; @@ -14,7 +34,6 @@ @DisplayName("Receiver should") final class ReceiverTest { - private static EmbeddedServer server; private static HttpClient client; @@ -38,7 +57,8 @@ public static void stopServer() { @Test void processIncomingWebHook() { - String actual = client.toBlocking().retrieve(HttpRequest.GET("/web-hook")); + String actual = client.toBlocking() + .retrieve(HttpRequest.GET("/web-hook")); assertEquals("OK", actual); } } From fd051806de4cd45832930c8cb47f98ccf84f3974 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 28 May 2020 20:00:59 +0300 Subject: [PATCH 007/492] Add copyright notices --- .gitignore | 20 +++++++++++++++++++ build.gradle | 20 +++++++++++++++++++ google-chat-bot/build.gradle | 20 +++++++++++++++++++ .../java/io/spine/chatbot/Application.java | 20 +++++++++++++++++++ .../spine/chatbot/github/identifiers.proto | 20 +++++++++++++++++++ .../spine/chatbot/github/organization.proto | 20 +++++++++++++++++++ .../github/organization_commands.proto | 20 +++++++++++++++++++ .../chatbot/github/organization_events.proto | 20 +++++++++++++++++++ .../spine/chatbot/github/repository.proto | 20 +++++++++++++++++++ .../chatbot/github/repository_commands.proto | 20 +++++++++++++++++++ .../chatbot/github/repository_events.proto | 20 +++++++++++++++++++ .../src/main/resources/application.yml | 20 +++++++++++++++++++ google-chat-bot/src/main/resources/log4j2.xml | 19 ++++++++++++++++++ gradle.properties | 19 ++++++++++++++++++ webhook-receiver/build.gradle | 20 +++++++++++++++++++ .../github/webhook/receiver/Application.java | 20 +++++++++++++++++++ .../src/main/resources/application.yml | 20 +++++++++++++++++++ .../src/main/resources/log4j2.xml | 19 ++++++++++++++++++ 18 files changed, 357 insertions(+) diff --git a/.gitignore b/.gitignore index 8500a032..abbac680 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,23 @@ +# +# Copyright 2020, TeamDev. All rights reserved. +# +# Redistribution and use in source and/or binary forms, with or without +# modification, must retain the above copyright notice and the following +# disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + Thumbs.db .DS_Store .gradle diff --git a/build.gradle b/build.gradle index 8496eeb4..d99d4ecd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + plugins { id "net.ltgt.apt" version "0.21" apply false id "com.github.johnrengelman.shadow" version "5.2.0" apply false diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 3937dfc4..662b7b10 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + apply plugin: 'io.spine.tools.gradle.bootstrap' spine { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 45281e3b..4d926304 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot; import io.micronaut.runtime.Micronaut; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index 9c5189b2..ceb7917c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index 539644c2..fd6ff440 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index e2826a27..040bf16c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index 8084b272..378c8020 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index b4d404a2..4f102d8b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 9ff84646..96b78a85 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 8da2a30e..8674c68f 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + syntax = "proto3"; package spine.chatbot.github; diff --git a/google-chat-bot/src/main/resources/application.yml b/google-chat-bot/src/main/resources/application.yml index 8a4def16..21a10d1c 100644 --- a/google-chat-bot/src/main/resources/application.yml +++ b/google-chat-bot/src/main/resources/application.yml @@ -1,3 +1,23 @@ +# +# Copyright 2020, TeamDev. All rights reserved. +# +# Redistribution and use in source and/or binary forms, with or without +# modification, must retain the above copyright notice and the following +# disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + micronaut: application: name: chatBot diff --git a/google-chat-bot/src/main/resources/log4j2.xml b/google-chat-bot/src/main/resources/log4j2.xml index 42f90d8e..fb134e31 100644 --- a/google-chat-bot/src/main/resources/log4j2.xml +++ b/google-chat-bot/src/main/resources/log4j2.xml @@ -1,4 +1,23 @@ + diff --git a/gradle.properties b/gradle.properties index c13712a0..777b84ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,21 @@ +# +# Copyright 2020, TeamDev. All rights reserved. +# +# Redistribution and use in source and/or binary forms, with or without +# modification, must retain the above copyright notice and the following +# disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# micronautVersion=2.0.0.M3 gcpProject='' \ No newline at end of file diff --git a/webhook-receiver/build.gradle b/webhook-receiver/build.gradle index c3e7dc5a..6094714a 100644 --- a/webhook-receiver/build.gradle +++ b/webhook-receiver/build.gradle @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + jib { to { image = "gcr.io/${gcpProject}/github-webhook-receiver" diff --git a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java index ce8bfc52..7bea0834 100644 --- a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java +++ b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.github.webhook.receiver; import io.micronaut.runtime.Micronaut; diff --git a/webhook-receiver/src/main/resources/application.yml b/webhook-receiver/src/main/resources/application.yml index 544b180f..cfaba24b 100644 --- a/webhook-receiver/src/main/resources/application.yml +++ b/webhook-receiver/src/main/resources/application.yml @@ -1,3 +1,23 @@ +# +# Copyright 2020, TeamDev. All rights reserved. +# +# Redistribution and use in source and/or binary forms, with or without +# modification, must retain the above copyright notice and the following +# disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + micronaut: application: name: webhookReceiver diff --git a/webhook-receiver/src/main/resources/log4j2.xml b/webhook-receiver/src/main/resources/log4j2.xml index 91520d6f..b1ea1984 100644 --- a/webhook-receiver/src/main/resources/log4j2.xml +++ b/webhook-receiver/src/main/resources/log4j2.xml @@ -1,4 +1,23 @@ + From 6428eb4de72add084f09f5ef09bd8719c090180a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 28 May 2020 21:54:45 +0300 Subject: [PATCH 008/492] Add visibility options --- .../src/main/proto/spine/chatbot/github/organization.proto | 1 + .../src/main/proto/spine/chatbot/github/repository.proto | 1 + 2 files changed, 2 insertions(+) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index fd6ff440..38e81bca 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -36,6 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub organization. message Organization { option (entity).kind = AGGREGATE; + option (entity).visibility = FULL; OrganizationId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 4f102d8b..1b62fa65 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -36,6 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub repository. message Repository { option (entity).kind = AGGREGATE; + option (entity).visibility = FULL; RepositoryId id = 1; From 356bb2837069b037513ad1e023d1b10c76e4404e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 28 May 2020 21:55:13 +0300 Subject: [PATCH 009/492] bump errorprone version --- build.gradle | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index d99d4ecd..e6b7249a 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ plugins { id 'com.google.cloud.tools.jib' version '2.3.0' apply false id "net.saliman.properties" version "1.5.1" apply false id 'io.spine.tools.gradle.bootstrap' version '1.5.8' apply false - id "net.ltgt.errorprone" version "1.1.1" apply false + id "net.ltgt.errorprone" version "1.2.0" apply false } allprojects { @@ -96,7 +96,15 @@ subprojects { tasks.withType(JavaCompile) { options.encoding = "UTF-8" - options.compilerArgs.add('-parameters') + options.compilerArgs.addAll("-Xlint:unchecked", "-Xlint:deprecation") + + options.errorprone + .errorproneArgs + .addAll('-XepExcludedPaths:.*/generated/.*', + '-Xep:ClassCanBeStatic:OFF', + '-Xep:UnusedMethod:OFF', + '-Xep:UnusedVariable:OFF', + '-Xep:CheckReturnValue:OFF') } tasks.withType(JavaExec) { From ee8a29e347512f129be4c890c907ca355acada95 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 28 May 2020 21:56:21 +0300 Subject: [PATCH 010/492] Define stub GitHub Context and refine Microunaut to start Spine server as well --- .../java/io/spine/chatbot/Application.java | 27 +++++- .../chatbot/ChatBotServerEnvironment.java | 42 +++++++++ .../chatbot/OrganizationsController.java | 48 ++++++++++ .../chatbot/server/github/GitHubContext.java | 88 +++++++++++++++++++ .../server/github/OrganizationAggregate.java | 53 +++++++++++ .../chatbot/server/github/package-info.java | 35 ++++++++ .../src/main/java/io/spine/net/Urls.java | 40 +++++++++ ....java => OrganizationsControllerTest.java} | 12 +-- .../server/github/GitHubContextTest.java | 32 +++++++ .../github/OrganizationAggregateTest.java | 65 ++++++++++++++ .../java/io/spine/net/UrlsTest.java} | 17 ++-- 11 files changed, 444 insertions(+), 15 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java create mode 100644 google-chat-bot/src/main/java/io/spine/net/Urls.java rename google-chat-bot/src/test/java/io/spine/chatbot/{HelloFunctionTest.java => OrganizationsControllerTest.java} (87%) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java rename google-chat-bot/src/{main/java/io/spine/chatbot/HelloController.java => test/java/io/spine/net/UrlsTest.java} (78%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 4d926304..2618af97 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -20,11 +20,36 @@ package io.spine.chatbot; +import com.google.common.annotations.VisibleForTesting; import io.micronaut.runtime.Micronaut; +import io.spine.chatbot.server.github.GitHubContext; +import io.spine.server.Server; -public class Application { +import java.io.IOException; + +public final class Application { + + static final String SERVER_NAME = "ChatBotServer"; + + private Application() { + } public static void main(String[] args) { + initializeSpine(); Micronaut.run(Application.class, args); } + + @VisibleForTesting + static void initializeSpine() { + ChatBotServerEnvironment.initializeEnvironment(); + Server server = Server + .inProcess(SERVER_NAME) + .add(GitHubContext.newBuilder()) + .build(); + try { + server.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java new file mode 100644 index 00000000..d40dcd7a --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot; + +import io.spine.server.ServerEnvironment; +import io.spine.server.delivery.Delivery; +import io.spine.server.storage.memory.InMemoryStorageFactory; +import io.spine.server.transport.memory.InMemoryTransportFactory; + +final class ChatBotServerEnvironment { + + /** + * Prevents instantiation of this utility class. + */ + private ChatBotServerEnvironment() { + } + + static void initializeEnvironment() { + ServerEnvironment se = ServerEnvironment.instance(); + se.configureStorage(InMemoryStorageFactory.newInstance()); + se.configureTransport(InMemoryTransportFactory.newInstance()); + se.configureDelivery(Delivery.localAsync()); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java new file mode 100644 index 00000000..3c1085c3 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.spine.chatbot.github.organization.Organization; +import io.spine.client.Client; + +import java.util.stream.Collectors; + +import static io.spine.chatbot.Application.SERVER_NAME; + +@Controller("/organizations") +public class OrganizationsController { + + @Get + public String index() { + Client client = Client + .inProcess(SERVER_NAME) + .build(); + String result = client.asGuest() + .select(Organization.class) + .run() + .stream() + .map(String::valueOf) + .collect(Collectors.joining()); + return result; + } +} \ No newline at end of file diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java new file mode 100644 index 00000000..cf500139 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -0,0 +1,88 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import com.google.errorprone.annotations.concurrent.LazyInit; +import io.spine.server.BoundedContext; +import io.spine.server.BoundedContextBuilder; +import io.spine.server.QueryService; +import io.spine.server.commandbus.CommandBus; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + +/** + * Provides BoundedContestBuilder for the GitHub Context. + */ +public final class GitHubContext { + + @MonotonicNonNull + @LazyInit + private static BoundedContext context = null; + + @MonotonicNonNull + @LazyInit + private static QueryService queryService = null; + + /** + * The name of the Context. + */ + static final String NAME = "GitHub"; + + /** + * Prevents instantiation of this utility class. + */ + private GitHubContext() { + } + + public static CommandBus commandBus() { + return context().commandBus(); + } + + public static synchronized QueryService queryService() { + if (queryService == null) { + queryService = QueryService + .newBuilder() + .add(context()) + .build(); + } + return queryService; + } + + public static synchronized BoundedContext context() { + if (context == null) { + context = newBuilder().build(); + } + return context; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + public static void initialize() { + queryService(); + } + + /** + * Creates a new instance of the GitHub Context builder. + */ + public static BoundedContextBuilder newBuilder() { + return BoundedContext + .singleTenant(NAME) + .add(OrganizationAggregate.class); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java new file mode 100644 index 00000000..195de772 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -0,0 +1,53 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.Organization; +import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.server.aggregate.Aggregate; +import io.spine.server.aggregate.Apply; +import io.spine.server.command.Assign; + +final class OrganizationAggregate + extends Aggregate { + + @Assign + OrganizationRegistered handle(RegisterOrganization c) { + return OrganizationRegistered + .newBuilder() + .setId(c.getId()) + .setGithubUrl(c.getGithubUrl()) + .setName(c.getName()) + .setTravisCiUrl(c.getTravisCiUrl()) + .setWebsiteUrl(c.getWebsiteUrl()) + .vBuild(); + } + + @Apply + private void on(OrganizationRegistered e) { + builder().setName(e.getName()) + .setGithubUrl(e.getGithubUrl()) + .setTravisCiUrl(e.getTravisCiUrl()) + .setWebsiteUrl(e.getWebsiteUrl()); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java new file mode 100644 index 00000000..2ef31c9f --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains server-side implementation of the GitHub Context. + * + *

This package is annotated with {@code BoundedContext} annotation to mark + * entities of this package (and sub-packages if they existed) as parts of the context. + */ +@BoundedContext(GitHubContext.NAME) +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.server.github; + +import com.google.errorprone.annotations.CheckReturnValue; +import io.spine.core.BoundedContext; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/google-chat-bot/src/main/java/io/spine/net/Urls.java b/google-chat-bot/src/main/java/io/spine/net/Urls.java new file mode 100644 index 00000000..4d7c2cc3 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/net/Urls.java @@ -0,0 +1,40 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.net; + +/** + * An utility for working with {@link Url}. + */ +public final class Urls { + + /** + * Prevents instantiation of this utility class. + */ + private Urls() { + } + + /** Creates a new {@link Url} out of supplied spec. **/ + public static Url urlOfSpec(String spec) { + return Url.newBuilder() + .setSpec(spec) + .vBuild(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java similarity index 87% rename from google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java index be98687f..663119f3 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/HelloFunctionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java @@ -29,16 +29,18 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.Application.initializeSpine; import static org.junit.jupiter.api.Assertions.assertEquals; @MicronautTest -final class HelloFunctionTest { +final class OrganizationsControllerTest { private static EmbeddedServer server; private static HttpClient client; @BeforeAll - public static void setupServer() { + static void setupServer() { + initializeSpine(); server = ApplicationContext.run(EmbeddedServer.class); client = server .getApplicationContext() @@ -46,7 +48,7 @@ public static void setupServer() { } @AfterAll - public static void stopServer() { + static void stopServer() { if (server != null) { server.stop(); } @@ -56,9 +58,9 @@ public static void stopServer() { } @Test - public void testFunction() { + void testFunction() { String actual = client.toBlocking() - .retrieve(HttpRequest.GET("/hello")); + .retrieve(HttpRequest.GET("/organizations")); assertEquals("Example Response", actual); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java new file mode 100644 index 00000000..871a91cd --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("GitHubContext should") +final class GitHubContextTest extends UtilityClassTest { + + GitHubContextTest() { + super(GitHubContext.class); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java new file mode 100644 index 00000000..5aff74d2 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.Organization; +import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.server.BoundedContextBuilder; +import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static io.spine.net.Urls.urlOfSpec; + +@DisplayName("Organization should") +final class OrganizationAggregateTest extends ContextAwareTest { + + @Override + protected BoundedContextBuilder contextBuilder() { + return GitHubContext.newBuilder(); + } + + @Test + void registerOrganization() { + OrganizationId organizationId = OrganizationId.generate(); + RegisterOrganization registerOrganization = RegisterOrganization + .newBuilder() + .setId(organizationId) + .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/TestOrganization")) + .setWebsiteUrl(urlOfSpec("https://test-organization.com")) + .setName("Test Organization") + .vBuild(); + context().receivesCommand(registerOrganization); + + Organization expectedState = Organization + .newBuilder() + .setId(organizationId) + .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/TestOrganization")) + .setWebsiteUrl(urlOfSpec("https://test-organization.com")) + .setName("Test Organization") + .vBuild(); + context().assertState(organizationId, Organization.class) + .isEqualTo(expectedState); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java similarity index 78% rename from google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java rename to google-chat-bot/src/test/java/io/spine/net/UrlsTest.java index 280bd588..1974b015 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/HelloController.java +++ b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java @@ -18,16 +18,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot; +package io.spine.net; -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Get; +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; -@Controller("/hello") -public class HelloController { +@DisplayName("Urls should") +final class UrlsTest extends UtilityClassTest { - @Get(uri = "/", produces = "text/plain") - public String index() { - return "Example Response"; + UrlsTest() { + super(Urls.class); } -} \ No newline at end of file +} From 5ad2014bfe92d85e80f1609c9e94b6105e088c51 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 14:33:49 +0300 Subject: [PATCH 011/492] Rename `name` to `slug` as we don't really need the repo name. --- .../src/main/proto/spine/chatbot/github/repository.proto | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 1b62fa65..9d8ab104 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -40,8 +40,10 @@ message Repository { RepositoryId id = 1; - // Name of the repository. - string name = 2; + // Slug of the repository. + // + // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. + string slug = 2; // GitHub URL of the repository. spine.net.Url github_url = 3; From 2f1d813a6ab0036adf1fc4616d7f941ac51d9508 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 14:52:43 +0300 Subject: [PATCH 012/492] Add example HTTP call for Travis API --- travis-ci.http | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 travis-ci.http diff --git a/travis-ci.http b/travis-ci.http new file mode 100644 index 00000000..3932db46 --- /dev/null +++ b/travis-ci.http @@ -0,0 +1,6 @@ +### + +GET https://api.travis-ci.com/repo/SpineEventEngine%2Fbase/builds?limit=1&branch.name=master +Accept: application/json +Authorization: token +Travis-API-Version: 3 From 8eb5771c0b7f7a64c4d57d8baef403469f98d798 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 15:40:35 +0300 Subject: [PATCH 013/492] Define minimal Travis CI entities representation. --- .../proto/spine/chatbot/travis/travis.proto | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto new file mode 100644 index 00000000..bfad387a --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -0,0 +1,129 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.travis; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.travis"; +option java_outer_classname = "TravisCiProto"; +option java_multiple_files = true; + +import "spine/time/time.proto"; +import "spine/core/user_id.proto"; + +message Owner { + + // Value uniquely identifying the owner. + uint64 id = 1; + + // User or organization login set on GitHub. + string login = 2; +} + +// An individual repository. +message Repository { + + // Value uniquely identifying the repository. + uint64 id = 1; + + // The repository's name on GitHub. + string name = 2; + + // The repository's slug. + // + // Same as {repository.owner.name}/{repository.name}. + string slug = 3; +} + +// The branch of a GitHub repository. +message Branch { + + // Name of the git branch. + string name = 1; +} + +// Commit information is obtained by requesting a build. +message Commit { + + // Value uniquely identifying the commit. + uint64 id = 1; + + // Checksum the commit has in git and is identified by. + string sha = 2; + + // Named reference the commit has in git. + string ref = 3; + + // Commit message. + string message = 4; + + // URL to the commit's diff on GitHub. + string compare_url = 5; + + // Commit date from git. + string committed_at = 6; +} + +// Minimal Travis CI build representation. +message Build { + + // Value uniquely identifying the build. + uint64 id = 1; + + // Incremental number for a repository's builds. + string number = 2; + + // Current state of the build. + string state = 3; + + // Wall clock time in seconds. + uint64 duration = 4; + + // Event that triggered the build. + string event_type = 5; + + // State of the previous build. + string previous_state = 6; + + // GitHub repository the build is associated with. + Repository repository = 7; + + // The branch the build is associated with. + Branch branch = 8; + + // The build's tag. + string tag = 9; + + // The commit the build is associated with. + Commit commit = 10; + + // The User or Organization that created the build. + Owner created_by = 11; +} + +// A Travis `builds` API endpoint response. +message BuildsResponse { + + repeated Build builds = 1; +} From 9253a39aefa6ab7fe7d2b58f86ad3074537149dc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 15:46:31 +0300 Subject: [PATCH 014/492] Add minimalistic Travis API client. --- .../travis/api/JsonProtoBodyHandler.java | 53 +++++++++++++ .../chatbot/travis/api/TravisClient.java | 79 +++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java new file mode 100644 index 00000000..80daa177 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java @@ -0,0 +1,53 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.travis.api; + +import com.google.protobuf.Message; +import io.spine.json.Json; + +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodySubscribers; +import java.net.http.HttpResponse.ResponseInfo; +import java.nio.charset.StandardCharsets; + +/** A {@link HttpResponse.BodyHandler BodyHandler} for JSON Protobuf messages. **/ +final class JsonProtoBodyHandler implements HttpResponse.BodyHandler { + + private final Class type; + + private JsonProtoBodyHandler(Class type) { + this.type = type; + } + + public static JsonProtoBodyHandler jsonBodyHandler(Class type) { + return new JsonProtoBodyHandler<>(type); + } + + @Override + public HttpResponse.BodySubscriber apply(ResponseInfo responseInfo) { + return BodySubscribers.mapping(BodySubscribers.ofString(StandardCharsets.UTF_8), + this::parseJson); + } + + private T parseJson(String json) { + return Json.fromJson(json, type); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java new file mode 100644 index 00000000..18b15103 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java @@ -0,0 +1,79 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.travis.api; + +import io.spine.chatbot.travis.BuildsResponse; + +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.nio.charset.StandardCharsets; + +import static io.spine.chatbot.travis.api.JsonProtoBodyHandler.jsonBodyHandler; + +final class TravisClient { + + private static final HttpClient CLIENT = HttpClient.newHttpClient(); + private static final String BASE_URL = "https://api.travis-ci.com"; + private static final String API_HEADER = "Travis-API-Version"; + private static final String API_VERSION = "3"; + private static final String AUTH_HEADER = "Authorization"; + + private final String apiToken; + + private TravisClient(String token) { + apiToken = token; + } + + public BuildsResponse queryBuildsFor(String repoSlug) { + var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); + var repoBuilds = "/repo/" + encodedSlug + "/builds?limit=1&branch.name=master"; + var request = apiRequest(repoBuilds, apiToken); + try { + var result = CLIENT.send(request, jsonBodyHandler(BuildsResponse.class)); + return result.body(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException("Unable to retrieve repository " + repoSlug + " builds.", e); + } + } + + private static HttpRequest apiRequest(String apiPath, String token) { + return authorizedApiRequest(token) + .uri(URI.create(BASE_URL + apiPath)) + .build(); + } + + private static HttpRequest.Builder authorizedApiRequest(String token) { + return HttpRequest + .newBuilder() + .GET() + .header(API_HEADER, API_VERSION) + .header(AUTH_HEADER, "token " + token); + } + + public static void main(String[] args) { + var client = new TravisClient(""); + var response = client.queryBuildsFor("SpineEventEngine/base"); + System.out.println(response); + } +} From 0e68936253ce19d2d358e3ce9b8b7a41fc42c653 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 15:49:44 +0300 Subject: [PATCH 015/492] Move to API package --- .../spine/chatbot/{travis => }/api/JsonProtoBodyHandler.java | 2 +- .../java/io/spine/chatbot/{travis => }/api/TravisClient.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{travis => }/api/JsonProtoBodyHandler.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/{travis => }/api/TravisClient.java (96%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java index 80daa177..1f8d0ac4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.travis.api; +package io.spine.chatbot.api; import com.google.protobuf.Message; import io.spine.json.Json; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index 18b15103..a5f5dc01 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.travis.api; +package io.spine.chatbot.api; import io.spine.chatbot.travis.BuildsResponse; @@ -29,7 +29,7 @@ import java.net.http.HttpRequest; import java.nio.charset.StandardCharsets; -import static io.spine.chatbot.travis.api.JsonProtoBodyHandler.jsonBodyHandler; +import static io.spine.chatbot.api.JsonProtoBodyHandler.jsonBodyHandler; final class TravisClient { From 09f172e8bcaac780acfe98b83bfa5321ae283f18 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 18:17:17 +0300 Subject: [PATCH 016/492] Add Hangouts Chat API dependency --- google-chat-bot/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 662b7b10..638a7f53 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -28,6 +28,8 @@ spine { } dependencies { + implementation 'com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9' + implementation 'com.google.auth:google-auth-library-oauth2-http:0.20.0' testImplementation "io.spine:spine-testutil-server:${spine.version()}" } From 4d253dcce32b00a5968a641fa124275a53fcff3d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 18:17:43 +0300 Subject: [PATCH 017/492] Create stub client --- .../spine/chatbot/api/GoogleChatClient.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java new file mode 100644 index 00000000..4d91d337 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -0,0 +1,68 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.chat.v1.HangoutsChat; +import com.google.api.services.chat.v1.model.Message; +import com.google.auth.http.HttpCredentialsAdapter; +import com.google.auth.oauth2.GoogleCredentials; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; + +public final class GoogleChatClient { + + private static final String BOT_NAME = "Spine Chat Bot"; + private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; + + private GoogleChatClient() { + } + + public static void main(String[] args) throws IOException, GeneralSecurityException { + var keyStream = Files.newInputStream(Paths.get("spine-chat-bot-ea2e6c200084.json")); + + var credentials = GoogleCredentials.fromStream(keyStream) + .createScoped(CHAT_BOT_SCOPE); + var credentialsAdapter = new HttpCredentialsAdapter(credentials); + var chat = new HangoutsChat.Builder( + GoogleNetHttpTransport.newTrustedTransport(), + JacksonFactory.getDefaultInstance(), + credentialsAdapter) + .setApplicationName(BOT_NAME) + .build(); + chat.spaces() + .list() + .execute() + .getSpaces() + .forEach(System.out::println); + var message = new Message() + .setName("test-message") + .setText("This is a test message from the Bot API."); + System.out.println(chat.spaces() + .messages() + .create("", message) + .execute()); + } +} From ab6d4dc0ce48c98d27895abb42327d5f482562b5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 18:56:40 +0300 Subject: [PATCH 018/492] Add Google Chat identifiers --- .../spine/chatbot/github/identifiers.proto | 3 -- .../chatbot/google/chat/identifiers.proto | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index ceb7917c..e1681ce8 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -29,9 +29,6 @@ option java_package = "io.spine.chatbot.github"; option java_outer_classname = "IdentifiersProto"; option java_multiple_files = true; -import "spine/time/time.proto"; -import "spine/core/user_id.proto"; - // Internal GitHub organization ID. message OrganizationId { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto new file mode 100644 index 00000000..a9ce77e2 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -0,0 +1,48 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat"; +option java_outer_classname = "IdentifiersProto"; +option java_multiple_files = true; + +// Hangouts Chat Space identifier. +message SpaceId { + + string uuid = 1 [(required) = true]; +} + +// Hangouts Chat Room identifier. +message RoomId { + + string uuid = 1 [(required) = true]; +} + +// Hangout Chat Room Thread identifier. +message ThreadId { + + string uuid = 1 [(required) = true]; +} From 0ac5bb26447fb43fd1ddd1983d1e5fc6240fb647 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 1 Jun 2020 19:03:19 +0300 Subject: [PATCH 019/492] add stub space proto --- .../spine/chatbot/google/chat/space.proto | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto new file mode 100644 index 00000000..e8bb34f7 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -0,0 +1,52 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat"; +option java_outer_classname = "IdentifiersProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +// A room or DM in Hangouts Chat. +message Space { + option (entity).kind = AGGREGATE; + option (entity).visibility = FULL; + + SpaceId id = 1; + + // Resource name of the space, in the form "spaces/*". + string name = 2; + + // Whether the space is a DM between a bot and a single human. + bool single_user_bot_dm = 3; + + // Whether the messages are threaded in this space. + bool threaded = 4; + + // The display name (only if the space is a room). + string display_name = 5; +} \ No newline at end of file From afb119f0da6e06f85812fde7fed60cc4da9754a1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 17:44:17 +0300 Subject: [PATCH 020/492] Use meaningful IDs. --- .../proto/spine/chatbot/github/identifiers.proto | 12 ++++++++---- .../spine/chatbot/google/chat/identifiers.proto | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index e1681ce8..8b57d702 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -29,14 +29,18 @@ option java_package = "io.spine.chatbot.github"; option java_outer_classname = "IdentifiersProto"; option java_multiple_files = true; -// Internal GitHub organization ID. +// GitHub organization ID. message OrganizationId { - string uuid = 1 [(required) = true]; + // Name of the GitHub organization. + string value = 1 [(required) = true]; } -// Internal GitHub repository ID. +// GitHub repository ID. message RepositoryId { - string uuid = 1 [(required) = true]; + // Slug of the repository. + // + // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. + string value = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto index a9ce77e2..ffd6eeca 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -32,13 +32,14 @@ option java_multiple_files = true; // Hangouts Chat Space identifier. message SpaceId { - string uuid = 1 [(required) = true]; + // Resource name of the space, in the form "spaces/*". + string value = 1 [(required) = true]; } // Hangouts Chat Room identifier. message RoomId { - string uuid = 1 [(required) = true]; + string value = 1 [(required) = true]; } // Hangout Chat Room Thread identifier. From 1042a681bdc73ece5708a49267173a0121685b4b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 17:44:28 +0300 Subject: [PATCH 021/492] Fix proto holder name --- .../src/main/proto/spine/chatbot/google/chat/space.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index e8bb34f7..7c04e34a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -26,7 +26,7 @@ import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat"; -option java_outer_classname = "IdentifiersProto"; +option java_outer_classname = "SpaceProto"; option java_multiple_files = true; import "spine/chatbot/google/chat/identifiers.proto"; From 4e150a8ffce05e8fa2c3d77fdcd754f87510e0a3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 17:44:44 +0300 Subject: [PATCH 022/492] Use meaningful org ID in test --- .../chatbot/server/github/OrganizationAggregateTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 5aff74d2..eefd24cc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -40,8 +40,11 @@ protected BoundedContextBuilder contextBuilder() { @Test void registerOrganization() { - OrganizationId organizationId = OrganizationId.generate(); - RegisterOrganization registerOrganization = RegisterOrganization + var organizationId = OrganizationId + .newBuilder() + .setValue("TestOrganization") + .vBuild(); + var registerOrganization = RegisterOrganization .newBuilder() .setId(organizationId) .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) @@ -51,7 +54,7 @@ void registerOrganization() { .vBuild(); context().receivesCommand(registerOrganization); - Organization expectedState = Organization + var expectedState = Organization .newBuilder() .setId(organizationId) .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) From 76d15ac06e0b93738c018a6d4d62c1d89cc60778 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 17:45:04 +0300 Subject: [PATCH 023/492] Define repository aggregate --- .../server/github/RepositoryAggregate.java | 76 +++++++++++++++++++ .../spine/chatbot/github/repository.proto | 64 +++++++++++++++- .../chatbot/github/repository_commands.proto | 9 +++ .../chatbot/github/repository_events.proto | 9 +++ 4 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java new file mode 100644 index 00000000..a30b3c06 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -0,0 +1,76 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.BuildStateChange; +import io.spine.chatbot.github.Repository; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.github.repository.command.SetBuildState; +import io.spine.chatbot.github.repository.event.BuildStateChanged; +import io.spine.chatbot.github.repository.event.RepositoryRegistered; +import io.spine.server.aggregate.Aggregate; +import io.spine.server.aggregate.Apply; +import io.spine.server.command.Assign; + +final class RepositoryAggregate + extends Aggregate { + + @Assign + RepositoryRegistered handle(RegisterRepository c) { + var result = RepositoryRegistered + .newBuilder() + .setId(c.getId()) + .setName(c.getName()) + .setGithubUrl(c.getGithubUrl()) + .setTravisCiUrl(c.getTravisCiUrl()) + .vBuild(); + return result; + } + + @Apply + private void on(RepositoryRegistered e) { + builder().setName(e.getName()) + .setGithubUrl(e.getGithubUrl()) + .setTravisCiUrl(e.getTravisCiUrl()); + } + + @Assign + BuildStateChanged handle(SetBuildState c) { + var stateChange = BuildStateChange + .newBuilder() + .setPreviousValue(state().getBuildState()) + .setNewValue(c.getBuildState()) + .vBuild(); + var result = BuildStateChanged + .newBuilder() + .setId(c.getId()) + .setChange(stateChange) + .vBuild(); + return result; + } + + @Apply + private void on(BuildStateChanged e) { + builder().setBuildState(e.getChange() + .getNewValue()); + } +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 9d8ab104..736708c6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -40,14 +40,70 @@ message Repository { RepositoryId id = 1; - // Slug of the repository. - // - // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. - string slug = 2; + // Name of the repository. + string name = 2; // GitHub URL of the repository. spine.net.Url github_url = 3; // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4; + + // Current state of the build. + BuildState build_state = 5; +} + +// State of the build for a repository branch. +message BuildState { + + // Incremental number for a repository's builds. + string number = 1; + + // Current state of the build. + Status status = 2; + + // State of the previous build. + Status previous_status = 3; + + // The branch the build is associated with. + string branch = 4; + + enum Status { + BS_STATUS_UNKNOWN = 0; + + PASSING = 1; + + FAILING = 2; + } + + // The commit the build is associated with. + Commit last_commit = 5; + + // The User or Organization that created the build. + string created_by = 6; + + message Commit { + + // Checksum the commit has in git and is identified by. + string sha = 1; + + // Commit message. + string message = 2; + + // URL to the commit's diff on GitHub. + string compare_url = 3; + + // Commit date from git. + string committed_at = 4; + } +} + +// Definition of a change in a `build_state` field. +message BuildStateChange { + + // The value of the field that's changing. + BuildState previous_value = 1; + + // The new value of the field. + BuildState new_value = 2 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 96b78a85..9b412b8d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -32,6 +32,7 @@ option java_multiple_files = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/repository.proto"; // Registers a new repository in the system. message RegisterRepository { @@ -47,3 +48,11 @@ message RegisterRepository { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; } + +// Sets the new build state of the repository. +message SetBuildState { + + RepositoryId id = 1 [(required) = true]; + + BuildState build_state = 2; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 8674c68f..070a90dc 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -32,6 +32,7 @@ option java_multiple_files = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/repository.proto"; // Denotes that a new repository is registered. message RepositoryRegistered { @@ -47,3 +48,11 @@ message RepositoryRegistered { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; } + +// Denotes that a build state was changed. +message BuildStateChanged { + + RepositoryId id = 1 [(required) = true]; + + BuildStateChange change = 2; +} From c70c0f20e5b5a6ff522c90fd5d7c6acab7fd4cc6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:42:16 +0300 Subject: [PATCH 024/492] Add link to the organization --- .../src/main/proto/spine/chatbot/github/repository.proto | 9 ++++++--- .../proto/spine/chatbot/github/repository_commands.proto | 3 +++ .../proto/spine/chatbot/github/repository_events.proto | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 736708c6..b5e26b1d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -25,8 +25,8 @@ package spine.chatbot.github; import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; -option java_package = "io.spine.chatbot.github"; -option java_outer_classname = "GithubOrganizationProto"; +option java_package = "io.spine.chatbot.github.repository"; +option java_outer_classname = "RepositoryProto"; option java_multiple_files = true; import "spine/net/url.proto"; @@ -49,8 +49,11 @@ message Repository { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4; + // ID of the organization repository is related to if any. + OrganizationId organization_id = 5; + // Current state of the build. - BuildState build_state = 5; + BuildState build_state = 6; } // State of the build for a repository branch. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 9b412b8d..cc9578d5 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -47,6 +47,9 @@ message RegisterRepository { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; + + // ID of the organization repository is related to if any. + OrganizationId organization_id = 5; } // Sets the new build state of the repository. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 070a90dc..2bdfaf11 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -47,6 +47,9 @@ message RepositoryRegistered { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; + + // ID of the organization repository is related to if any. + OrganizationId organization_id = 5; } // Denotes that a build state was changed. From 8a22e6b8462d6ad4026d44701302993a83744083 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:42:33 +0300 Subject: [PATCH 025/492] Add OrgRepos projection --- .../spine/chatbot/github/identifiers.proto | 6 +++ .../github/organization_repositories.proto | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index 8b57d702..9ad63705 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -44,3 +44,9 @@ message RepositoryId { // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. string value = 1 [(required) = true]; } + +// Organization repositories projection ID. +message OrganizationRepositoriesId { + + OrganizationId org_id = 1 [(required) = true]; +} \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto new file mode 100644 index 00000000..3fef199d --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -0,0 +1,45 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.organization"; +option java_outer_classname = "OrganizationProto"; +option java_multiple_files = true; + +import "spine/net/url.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +// A GitHub organization. +message OrganizationRepositories { + option (entity).kind = PROJECTION; + option (entity).visibility = FULL; + + OrganizationRepositoriesId id = 1; + + // Linked organization repositories. + repeated RepositoryId repositories = 2; +} From f8c0b118a5469abc713604e36c03a0b046fb630f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:44:55 +0300 Subject: [PATCH 026/492] Fix proto holder name --- .../proto/spine/chatbot/github/organization_repositories.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 3fef199d..bc3db5b7 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -26,7 +26,7 @@ import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization"; -option java_outer_classname = "OrganizationProto"; +option java_outer_classname = "OrganizationRepositoriesProto"; option java_multiple_files = true; import "spine/net/url.proto"; From 2f474748156d17498198dc93ddc333afdae94c27 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:45:16 +0300 Subject: [PATCH 027/492] Remove unused imports --- .../proto/spine/chatbot/github/organization_repositories.proto | 2 -- .../src/main/proto/spine/chatbot/travis/travis.proto | 3 --- 2 files changed, 5 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index bc3db5b7..8c7c1886 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -29,8 +29,6 @@ option java_package = "io.spine.chatbot.github.organization"; option java_outer_classname = "OrganizationRepositoriesProto"; option java_multiple_files = true; -import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; // A GitHub organization. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index bfad387a..4b9ff541 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -29,9 +29,6 @@ option java_package = "io.spine.chatbot.travis"; option java_outer_classname = "TravisCiProto"; option java_multiple_files = true; -import "spine/time/time.proto"; -import "spine/core/user_id.proto"; - message Owner { // Value uniquely identifying the owner. From 06450cb60d98fc6c63d54da2fb998958086dfab5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:47:17 +0300 Subject: [PATCH 028/492] fix imports --- .../io/spine/chatbot/server/github/RepositoryAggregate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java index a30b3c06..8817f035 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -20,9 +20,9 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.github.BuildStateChange; -import io.spine.chatbot.github.Repository; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.BuildStateChange; +import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.github.repository.command.SetBuildState; import io.spine.chatbot.github.repository.event.BuildStateChanged; From febd2d4fb14079f47e96692ade19ce392fbf628f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:51:52 +0300 Subject: [PATCH 029/492] Add repository aggregate stub test --- .../chatbot/server/github/GitHubContext.java | 3 +- .../github/RepositoryAggregateTest.java | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index cf500139..c27aa473 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -83,6 +83,7 @@ public static void initialize() { public static BoundedContextBuilder newBuilder() { return BoundedContext .singleTenant(NAME) - .add(OrganizationAggregate.class); + .add(OrganizationAggregate.class) + .add(RepositoryAggregate.class); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java new file mode 100644 index 00000000..1d213b3b --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.Repository; +import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.server.BoundedContextBuilder; +import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static io.spine.net.Urls.urlOfSpec; + +@DisplayName("Repository should") +public class RepositoryAggregateTest extends ContextAwareTest { + + @Override + protected BoundedContextBuilder contextBuilder() { + return GitHubContext.newBuilder(); + } + + @Test + void registerOrganization() { + var id = RepositoryId + .newBuilder() + .setValue("SpineEventEngine/base") + .vBuild(); + var registerRepository = RegisterRepository + .newBuilder() + .setId(id) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) + .setName("Spine base") + .vBuild(); + context().receivesCommand(registerRepository); + + var expectedState = Repository + .newBuilder() + .setId(id) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) + .setName("Spine base") + .vBuild(); + context().assertState(id, Repository.class) + .isEqualTo(expectedState); + } +} From dccd319608a89e32919f95e66f5d56cf9195e7ff Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:59:07 +0300 Subject: [PATCH 030/492] Add stub Google Chat context and Space aggregate --- .../java/io/spine/chatbot/Application.java | 2 + .../spine/chatbot/api/GoogleChatClient.java | 3 +- .../server/google/chat/GoogleChatContext.java | 85 +++++++++++++++++++ .../server/google/chat/SpaceAggregate.java | 53 ++++++++++++ .../server/google/chat/package-info.java | 35 ++++++++ .../chatbot/google/chat/space_commands.proto | 49 +++++++++++ .../chatbot/google/chat/space_events.proto | 49 +++++++++++ .../google/chat/GoogleChatContextTest.java | 32 +++++++ .../google/chat/SpaceAggregateTest.java | 65 ++++++++++++++ 9 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 2618af97..b15d18ed 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting; import io.micronaut.runtime.Micronaut; import io.spine.chatbot.server.github.GitHubContext; +import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.server.Server; import java.io.IOException; @@ -45,6 +46,7 @@ static void initializeSpine() { Server server = Server .inProcess(SERVER_NAME) .add(GitHubContext.newBuilder()) + .add(GoogleChatContext.newBuilder()) .build(); try { server.start(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 4d91d337..04a8874d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -58,11 +58,10 @@ public static void main(String[] args) throws IOException, GeneralSecurityExcept .getSpaces() .forEach(System.out::println); var message = new Message() - .setName("test-message") .setText("This is a test message from the Bot API."); System.out.println(chat.spaces() .messages() - .create("", message) + .create("spaces/4H4sJgAAAAE", message) .execute()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java new file mode 100644 index 00000000..3ceaf0db --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -0,0 +1,85 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import com.google.errorprone.annotations.concurrent.LazyInit; +import io.spine.server.BoundedContext; +import io.spine.server.BoundedContextBuilder; +import io.spine.server.QueryService; +import io.spine.server.commandbus.CommandBus; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + +public final class GoogleChatContext { + + @MonotonicNonNull + @LazyInit + private static BoundedContext context = null; + + @MonotonicNonNull + @LazyInit + private static QueryService queryService = null; + + /** + * The name of the Context. + */ + static final String NAME = "GoogleChat"; + + /** + * Prevents instantiation of this utility class. + */ + private GoogleChatContext() { + } + + public static CommandBus commandBus() { + return context().commandBus(); + } + + public static synchronized QueryService queryService() { + if (queryService == null) { + queryService = QueryService + .newBuilder() + .add(context()) + .build(); + } + return queryService; + } + + public static synchronized BoundedContext context() { + if (context == null) { + context = newBuilder().build(); + } + return context; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + public static void initialize() { + queryService(); + } + + /** + * Creates a new instance of the GitHub Context builder. + */ + public static BoundedContextBuilder newBuilder() { + return BoundedContext + .singleTenant(NAME) + .add(SpaceAggregate.class); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java new file mode 100644 index 00000000..025b3e28 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -0,0 +1,53 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.Space; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.command.RegisterSpace; +import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.server.aggregate.Aggregate; +import io.spine.server.aggregate.Apply; +import io.spine.server.command.Assign; + +final class SpaceAggregate extends Aggregate { + + @Assign + SpaceRegistered handle(RegisterSpace c) { + var result = SpaceRegistered + .newBuilder() + .setId(c.getId()) + .setName(c.getName()) + .setSingleUserBotDm(c.getSingleUserBotDm()) + .setThreaded(c.getThreaded()) + .setDisplayName(c.getDisplayName()) + .vBuild(); + return result; + } + + @Apply + private void on(SpaceRegistered e) { + builder().setName(e.getName()) + .setDisplayName(e.getDisplayName()) + .setSingleUserBotDm(e.getSingleUserBotDm()) + .setThreaded(e.getThreaded()); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java new file mode 100644 index 00000000..677628af --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains server-side implementation of the Google Chat Context. + * + *

This package is annotated with {@code BoundedContext} annotation to mark + * entities of this package (and sub-packages if they existed) as parts of the context. + */ +@BoundedContext(GoogleChatContext.NAME) +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.server.google.chat; + +import com.google.errorprone.annotations.CheckReturnValue; +import io.spine.core.BoundedContext; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto new file mode 100644 index 00000000..76500cab --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -0,0 +1,49 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.command"; +option java_outer_classname = "SpaceCommandsProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +message RegisterSpace { + + SpaceId id = 1 [(required) = true]; + + // Resource name of the space, in the form "spaces/*". + string name = 2 [(required) = true]; + + // Whether the space is a DM between a bot and a single human. + bool single_user_bot_dm = 3; + + // Whether the messages are threaded in this space. + bool threaded = 4; + + // The display name (only if the space is a room). + string display_name = 5; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto new file mode 100644 index 00000000..3c7f5aa1 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -0,0 +1,49 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.event"; +option java_outer_classname = "SpaceEventsProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +message SpaceRegistered { + + SpaceId id = 1 [(required) = true]; + + // Resource name of the space, in the form "spaces/*". + string name = 2 [(required) = true]; + + // Whether the space is a DM between a bot and a single human. + bool single_user_bot_dm = 3; + + // Whether the messages are threaded in this space. + bool threaded = 4; + + // The display name (only if the space is a room). + string display_name = 5; +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java new file mode 100644 index 00000000..db63be8f --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("GoogleChatContext should") +final class GoogleChatContextTest extends UtilityClassTest { + + GoogleChatContextTest() { + super(GoogleChatContext.class); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java new file mode 100644 index 00000000..2de3f812 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.Space; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.command.RegisterSpace; +import io.spine.server.BoundedContextBuilder; +import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("SpaceAggregate should") +final class SpaceAggregateTest extends ContextAwareTest { + + @Override + protected BoundedContextBuilder contextBuilder() { + return GoogleChatContext.newBuilder(); + } + + @Test + @DisplayName("register a space") + void register() { + var id = SpaceId + .newBuilder() + .setValue("spaces/qwroi12h3") + .vBuild(); + var registerOrganization = RegisterSpace + .newBuilder() + .setId(id) + .setName(id.getValue()) + .setThreaded(true) + .setDisplayName("Spine Developers") + .vBuild(); + context().receivesCommand(registerOrganization); + + var expectedState = Space + .newBuilder() + .setId(id) + .setName(id.getValue()) + .setThreaded(true) + .setDisplayName("Spine Developers") + .vBuild(); + context().assertState(id, Space.class) + .isEqualTo(expectedState); + } +} From ab01bd685662b5cb80c3cadf3567b76a2f3f506c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 2 Jun 2020 18:59:14 +0300 Subject: [PATCH 031/492] cleanup --- .../server/github/OrganizationAggregateTest.java | 13 +++++++------ .../server/github/RepositoryAggregateTest.java | 7 ++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index eefd24cc..9a471779 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -30,7 +30,7 @@ import static io.spine.net.Urls.urlOfSpec; -@DisplayName("Organization should") +@DisplayName("OrganizationAggregate should") final class OrganizationAggregateTest extends ContextAwareTest { @Override @@ -39,14 +39,15 @@ protected BoundedContextBuilder contextBuilder() { } @Test - void registerOrganization() { - var organizationId = OrganizationId + @DisplayName("register an organization") + void register() { + var id = OrganizationId .newBuilder() .setValue("TestOrganization") .vBuild(); var registerOrganization = RegisterOrganization .newBuilder() - .setId(organizationId) + .setId(id) .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) .setTravisCiUrl(urlOfSpec("https://travis-ci.com/TestOrganization")) .setWebsiteUrl(urlOfSpec("https://test-organization.com")) @@ -56,13 +57,13 @@ void registerOrganization() { var expectedState = Organization .newBuilder() - .setId(organizationId) + .setId(id) .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) .setTravisCiUrl(urlOfSpec("https://travis-ci.com/TestOrganization")) .setWebsiteUrl(urlOfSpec("https://test-organization.com")) .setName("Test Organization") .vBuild(); - context().assertState(organizationId, Organization.class) + context().assertState(id, Organization.class) .isEqualTo(expectedState); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 1d213b3b..db823ae2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -30,8 +30,8 @@ import static io.spine.net.Urls.urlOfSpec; -@DisplayName("Repository should") -public class RepositoryAggregateTest extends ContextAwareTest { +@DisplayName("RepositoryAggregate should") +final class RepositoryAggregateTest extends ContextAwareTest { @Override protected BoundedContextBuilder contextBuilder() { @@ -39,7 +39,8 @@ protected BoundedContextBuilder contextBuilder() { } @Test - void registerOrganization() { + @DisplayName("register a repository") + void register() { var id = RepositoryId .newBuilder() .setValue("SpineEventEngine/base") From 3f9427f0194d635fe09837cd8a59adb84a5ed971 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 3 Jun 2020 15:21:46 +0300 Subject: [PATCH 032/492] Use org ID instead of custom wrapper --- .../chatbot/server/github/GitHubContext.java | 3 +- .../OrganizationRepositoriesProjection.java | 42 ++++++++++++++++ .../OrganizationRepositoriesRepository.java | 48 +++++++++++++++++++ .../spine/chatbot/github/identifiers.proto | 6 --- .../github/organization_repositories.proto | 2 +- 5 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index c27aa473..61cac5fa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -84,6 +84,7 @@ public static BoundedContextBuilder newBuilder() { return BoundedContext .singleTenant(NAME) .add(OrganizationAggregate.class) - .add(RepositoryAggregate.class); + .add(RepositoryAggregate.class) + .add(new OrganizationRepositoriesRepository()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java new file mode 100644 index 00000000..3e6f1e7d --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.chatbot.github.repository.event.RepositoryRegistered; +import io.spine.core.Subscribe; +import io.spine.server.projection.Projection; + +final class OrganizationRepositoriesProjection + extends Projection { + + @Subscribe + void on(OrganizationRegistered e) { + builder().setId(e.getId()); + } + + @Subscribe + void on(RepositoryRegistered e) { + builder().addRepositories(e.getId()); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java new file mode 100644 index 00000000..a042025e --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.chatbot.github.repository.event.RepositoryRegistered; +import io.spine.server.projection.ProjectionRepository; +import io.spine.server.route.EventRouting; + +import static io.spine.protobuf.Messages.isNotDefault; +import static io.spine.server.route.EventRoute.noTargets; +import static io.spine.server.route.EventRoute.withId; + +final class OrganizationRepositoriesRepository + extends ProjectionRepository { + + @OverridingMethodsMustInvokeSuper + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(RepositoryRegistered.class, (event, context) -> + isNotDefault(event.getOrganizationId()) + ? withId(event.getOrganizationId()) + : noTargets()); + } +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index 9ad63705..8b57d702 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -44,9 +44,3 @@ message RepositoryId { // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. string value = 1 [(required) = true]; } - -// Organization repositories projection ID. -message OrganizationRepositoriesId { - - OrganizationId org_id = 1 [(required) = true]; -} \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 8c7c1886..ef912fb7 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -36,7 +36,7 @@ message OrganizationRepositories { option (entity).kind = PROJECTION; option (entity).visibility = FULL; - OrganizationRepositoriesId id = 1; + OrganizationId id = 1; // Linked organization repositories. repeated RepositoryId repositories = 2; From 076a16e9a2a3d4636298543cf58d1822807e4345 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 3 Jun 2020 16:48:55 +0300 Subject: [PATCH 033/492] Compile a card out of raw texts --- .../spine/chatbot/api/GoogleChatClient.java | 96 ++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 04a8874d..7672c914 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -23,9 +23,24 @@ import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.chat.v1.HangoutsChat; +import com.google.api.services.chat.v1.model.Button; +import com.google.api.services.chat.v1.model.Card; +import com.google.api.services.chat.v1.model.CardHeader; import com.google.api.services.chat.v1.model.Message; +import com.google.api.services.chat.v1.model.OnClick; +import com.google.api.services.chat.v1.model.OpenLink; +import com.google.api.services.chat.v1.model.Section; +import com.google.api.services.chat.v1.model.TextButton; +import com.google.api.services.chat.v1.model.TextParagraph; +import com.google.api.services.chat.v1.model.Thread; +import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import io.spine.chatbot.github.repository.BuildState; +import io.spine.net.Url; +import io.spine.net.Urls; import java.io.IOException; import java.nio.file.Files; @@ -57,11 +72,88 @@ public static void main(String[] args) throws IOException, GeneralSecurityExcept .execute() .getSpaces() .forEach(System.out::println); + var commit = BuildState.Commit + .newBuilder() + .setMessage("My test commit") + .setSha("d97c603d5e855d0d211382f78916ad085ba04743") + .setCompareUrl( + "https://github.com/SpineEventEngine/base/commit/d97c603d5e855d0d211382f78916ad085ba04743") + .vBuild(); var message = new Message() - .setText("This is a test message from the Bot API."); + .setThread(new Thread().setName("spaces/AAAAnLxnh_o/threads/TPFMA4dK0_4")) + .setCards(ImmutableList.of( + new Card() + .setHeader(new CardHeader().setTitle("SpineEventEngine/base")) + .setSections(ImmutableList.of( + new Section() + .setHeader("Build failed in master.") + .setWidgets(ImmutableList.of( + new WidgetMarkup() + .setTextParagraph( + new TextParagraph().setText( + "First text paragraph")), + commitInfo(commit), + buttons( + linkButton("Build status", + Urls.urlOfSpec( + "https://travis-ci.com/github/SpineEventEngine/base/builds/169043750")), + linkButton("Changeset", + Urls.urlOfSpec( + "https://github.com/SpineEventEngine/base/compare/8a042f66b8c9...d97c603d5e85" + ))) + ) + ) + ) + )) + ) +// .setPreviewText("This is a test.") + .setText(namedLink("https://google.com", "GOOGLE!")); System.out.println(chat.spaces() .messages() - .create("spaces/4H4sJgAAAAE", message) + .create("spaces/AAAAnLxnh_o", message) .execute()); } + + private static CardHeader cardHeader(String title, String subTitle) { + return new CardHeader().setTitle(title) + .setSubtitle(subTitle); + } + + private static WidgetMarkup commitInfo(BuildState.Commit commit) { + var message = commit.getMessage(); + var sha = commit.getSha(); + var url = commit.getCompareUrl(); + var paragraphMessage = new StringBuilder("Commit ") + .append('`') + .append(sha) + .append('`') + .append(" with message ") + .append('`') + .append(message) + .append('`') + .append(" has broken the build.") + .append('\n') + .append("The diff is available ") + .append(namedLink(url, "here")) + .append('.') + .toString(); + return new WidgetMarkup().setTextParagraph(new TextParagraph().setText(paragraphMessage)); + } + + private static String namedLink(String url, String title) { + return "" + title + ""; + } + + private static WidgetMarkup buttons(Button first, Button... rest) { + return new WidgetMarkup().setButtons(Lists.asList(first, rest)); + } + + private static Button linkButton(String title, Url url) { + return new Button().setTextButton(new TextButton().setText(title) + .setOnClick(openLink(url))); + } + + private static OnClick openLink(Url url) { + return new OnClick().setOpenLink(new OpenLink().setUrl(url.getSpec())); + } } From 8951efa0ce6dd3d32edac607fd9f6b0b9f69cf0a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 3 Jun 2020 18:42:14 +0300 Subject: [PATCH 034/492] Use Url type for links. Add travis URL to BuildState --- .../proto/spine/chatbot/github/repository.proto | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index b5e26b1d..56d43c3e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -62,14 +62,17 @@ message BuildState { // Incremental number for a repository's builds. string number = 1; + // Travis CI URL of the build. + spine.net.Url travis_ci_url = 2; + // Current state of the build. - Status status = 2; + Status status = 3; // State of the previous build. - Status previous_status = 3; + Status previous_status = 4; // The branch the build is associated with. - string branch = 4; + string branch = 5; enum Status { BS_STATUS_UNKNOWN = 0; @@ -80,10 +83,10 @@ message BuildState { } // The commit the build is associated with. - Commit last_commit = 5; + Commit last_commit = 6; // The User or Organization that created the build. - string created_by = 6; + string created_by = 7; message Commit { @@ -94,7 +97,7 @@ message BuildState { string message = 2; // URL to the commit's diff on GitHub. - string compare_url = 3; + spine.net.Url compare_url = 3; // Commit date from git. string committed_at = 4; From 13ae5c08611c3068889621d279a3d28cab55abd5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 12:54:59 +0300 Subject: [PATCH 035/492] Add repo slug to build state --- .../src/main/proto/spine/chatbot/github/repository.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 56d43c3e..14acb209 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -102,6 +102,9 @@ message BuildState { // Commit date from git. string committed_at = 4; } + + // The repository slug the builds is associated with. + string repository_slug = 8; } // Definition of a change in a `build_state` field. From 26ecf584fd34b36f010296c6573315443629962d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:01:36 +0300 Subject: [PATCH 036/492] Extract reusable chat message parts. Cleanup code. --- .../spine/chatbot/api/GoogleChatClient.java | 194 ++++++++++-------- 1 file changed, 107 insertions(+), 87 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 7672c914..d4793f42 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -26,26 +26,30 @@ import com.google.api.services.chat.v1.model.Button; import com.google.api.services.chat.v1.model.Card; import com.google.api.services.chat.v1.model.CardHeader; +import com.google.api.services.chat.v1.model.KeyValue; import com.google.api.services.chat.v1.model.Message; import com.google.api.services.chat.v1.model.OnClick; import com.google.api.services.chat.v1.model.OpenLink; import com.google.api.services.chat.v1.model.Section; +import com.google.api.services.chat.v1.model.Space; import com.google.api.services.chat.v1.model.TextButton; -import com.google.api.services.chat.v1.model.TextParagraph; import com.google.api.services.chat.v1.model.Thread; import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.BuildState; import io.spine.net.Url; import io.spine.net.Urls; +import javax.annotation.Nullable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.GeneralSecurityException; +import java.util.List; public final class GoogleChatClient { @@ -55,105 +59,121 @@ public final class GoogleChatClient { private GoogleChatClient() { } - public static void main(String[] args) throws IOException, GeneralSecurityException { - var keyStream = Files.newInputStream(Paths.get("spine-chat-bot-ea2e6c200084.json")); - - var credentials = GoogleCredentials.fromStream(keyStream) - .createScoped(CHAT_BOT_SCOPE); - var credentialsAdapter = new HttpCredentialsAdapter(credentials); - var chat = new HangoutsChat.Builder( - GoogleNetHttpTransport.newTrustedTransport(), - JacksonFactory.getDefaultInstance(), - credentialsAdapter) - .setApplicationName(BOT_NAME) - .build(); - chat.spaces() - .list() - .execute() - .getSpaces() - .forEach(System.out::println); - var commit = BuildState.Commit - .newBuilder() - .setMessage("My test commit") - .setSha("d97c603d5e855d0d211382f78916ad085ba04743") - .setCompareUrl( - "https://github.com/SpineEventEngine/base/commit/d97c603d5e855d0d211382f78916ad085ba04743") - .vBuild(); - var message = new Message() - .setThread(new Thread().setName("spaces/AAAAnLxnh_o/threads/TPFMA4dK0_4")) - .setCards(ImmutableList.of( - new Card() - .setHeader(new CardHeader().setTitle("SpineEventEngine/base")) - .setSections(ImmutableList.of( - new Section() - .setHeader("Build failed in master.") - .setWidgets(ImmutableList.of( - new WidgetMarkup() - .setTextParagraph( - new TextParagraph().setText( - "First text paragraph")), - commitInfo(commit), - buttons( - linkButton("Build status", - Urls.urlOfSpec( - "https://travis-ci.com/github/SpineEventEngine/base/builds/169043750")), - linkButton("Changeset", - Urls.urlOfSpec( - "https://github.com/SpineEventEngine/base/compare/8a042f66b8c9...d97c603d5e85" - ))) - ) - ) - ) - )) - ) -// .setPreviewText("This is a test.") - .setText(namedLink("https://google.com", "GOOGLE!")); - System.out.println(chat.spaces() - .messages() - .create("spaces/AAAAnLxnh_o", message) - .execute()); + private static HangoutsChat hangoutsChat() { + try { + var keyStream = Files.newInputStream(Paths.get("spine-chat-bot-ea2e6c200084.json")); + + var credentials = GoogleCredentials.fromStream(keyStream) + .createScoped(CHAT_BOT_SCOPE); + var credentialsAdapter = new HttpCredentialsAdapter(credentials); + var chat = new HangoutsChat.Builder( + GoogleNetHttpTransport.newTrustedTransport(), + JacksonFactory.getDefaultInstance(), + credentialsAdapter) + .setApplicationName(BOT_NAME) + .build(); + return chat; + } catch (IOException | GeneralSecurityException e) { + throw new RuntimeException("Unable to create Hangouts Chat client", e); + } + } + + private static List listSpaces(HangoutsChat chat) { + try { + return chat.spaces() + .list() + .execute() + .getSpaces(); + } catch (IOException e) { + throw new RuntimeException("Unable to retrieve available spaces.", e); + } } - private static CardHeader cardHeader(String title, String subTitle) { - return new CardHeader().setTitle(title) - .setSubtitle(subTitle); + @CanIgnoreReturnValue + private static Message sendMessage(HangoutsChat chat, String space, Message message) { + try { + return chat.spaces() + .messages() + .create(space, message) + .execute(); + } catch (IOException e) { + throw new RuntimeException("Unable to send message to space " + space, e); + } } - private static WidgetMarkup commitInfo(BuildState.Commit commit) { - var message = commit.getMessage(); - var sha = commit.getSha(); - var url = commit.getCompareUrl(); - var paragraphMessage = new StringBuilder("Commit ") - .append('`') - .append(sha) - .append('`') - .append(" with message ") - .append('`') - .append(message) - .append('`') - .append(" has broken the build.") - .append('\n') - .append("The diff is available ") - .append(namedLink(url, "here")) - .append('.') - .toString(); - return new WidgetMarkup().setTextParagraph(new TextParagraph().setText(paragraphMessage)); + private static ImmutableList cardWith(CardHeader header, List

sections) { + return ImmutableList.of(new Card().setHeader(header) + .setSections(sections)); } - private static String namedLink(String url, String title) { - return "" + title + ""; + private static Section sectionWithWidget(WidgetMarkup widget) { + return new Section().setWidgets(List.of(widget)); } - private static WidgetMarkup buttons(Button first, Button... rest) { - return new WidgetMarkup().setButtons(Lists.asList(first, rest)); + private static WidgetMarkup commitWidget(BuildState.Commit commit) { + var keyValue = new KeyValue() + .setTopLabel("Commit") + .setContent(commit.getMessage()) + .setBottomLabel(commit.getSha()) + .setButton(linkButton("Changes", commit.getCompareUrl())); + return new WidgetMarkup().setKeyValue(keyValue); + } + + private static WidgetMarkup buildStateWidget(BuildState buildState) { + var keyValue = new KeyValue() + .setTopLabel("Build No.") + .setContent(buildState.getNumber()) + .setBottomLabel("Failed") + .setButton(linkButton("Build", Urls.urlOfSpec("https://google.com"))); + return new WidgetMarkup().setKeyValue(keyValue); } private static Button linkButton(String title, Url url) { - return new Button().setTextButton(new TextButton().setText(title) - .setOnClick(openLink(url))); + var button = new TextButton().setText(title) + .setOnClick(openLink(url)); + return new Button().setTextButton(button); } private static OnClick openLink(Url url) { return new OnClick().setOpenLink(new OpenLink().setUrl(url.getSpec())); } + + private static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { + var cardHeader = new CardHeader() + .setTitle("SpineEventEngine/base") + .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); + var sections = ImmutableList.of( + sectionWithWidget(buildStateWidget(buildState)), + sectionWithWidget(commitWidget(buildState.getLastCommit())) + ); + var message = new Message() + .setCards(cardWith(cardHeader, sections)); + if (Strings.isNullOrEmpty(threadName)) { + message.setThread(new Thread().setName(threadName)); + } + return message; + } + + public static void main(String[] args) { + var chat = hangoutsChat(); + listSpaces(chat).forEach(System.out::println); + var commit = BuildState.Commit + .newBuilder() + .setMessage("My test commit") + .setSha("d97c603d5e855d0d211382f78916ad085ba04743") + .setCompareUrl(Urls.urlOfSpec( + "https://github.com/SpineEventEngine/base/commit/d97c603d5e855d0d211382f78916ad085ba04743")) + .vBuild(); + BuildState buildState = BuildState + .newBuilder() + .setNumber("5292") + .setLastCommit(commit) + .setTravisCiUrl(Urls.urlOfSpec( + "https://travis-ci.com/github/SpineEventEngine/base/builds/166723382")) + .setBranch("master") + .setCreatedBy("yuri-sergiichuk") + .vBuild(); + Message message = buildStateMessage(buildState, "spaces/AAAAnLxnh_o/threads/TPFMA4dK0_4"); + sendMessage(chat, "spaces/AAAAnLxnh_o", message); + } } From 39dcc18651808ccf662b24e0f0882dbbedd95c19 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:02:52 +0300 Subject: [PATCH 037/492] Use supplied repo slug --- .../src/main/java/io/spine/chatbot/api/GoogleChatClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index d4793f42..2080ae50 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -140,7 +140,7 @@ private static OnClick openLink(Url url) { private static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { var cardHeader = new CardHeader() - .setTitle("SpineEventEngine/base") + .setTitle(buildState.getRepositorySlug()) .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); var sections = ImmutableList.of( sectionWithWidget(buildStateWidget(buildState)), @@ -166,6 +166,7 @@ public static void main(String[] args) { .vBuild(); BuildState buildState = BuildState .newBuilder() + .setRepositorySlug("SpineEventEngine/base") .setNumber("5292") .setLastCommit(commit) .setTravisCiUrl(Urls.urlOfSpec( From e51a844dc021c4ad198e9c3beeb8d3f57a57b1e7 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:07:28 +0300 Subject: [PATCH 038/492] Use status from Build State --- .../io/spine/chatbot/api/GoogleChatClient.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 2080ae50..bd192dae 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -43,6 +43,7 @@ import io.spine.chatbot.github.repository.BuildState; import io.spine.net.Url; import io.spine.net.Urls; +import io.spine.validate.Validate; import javax.annotation.Nullable; import java.io.IOException; @@ -120,10 +121,23 @@ private static WidgetMarkup commitWidget(BuildState.Commit commit) { } private static WidgetMarkup buildStateWidget(BuildState buildState) { + String status = null; + switch (buildState.getStatus()) { + case PASSING: + status = "Passing"; + break; + case FAILING: + status = "Failing"; + break; + case BS_STATUS_UNKNOWN: + case UNRECOGNIZED: + default: + status = "Undefined status"; + } var keyValue = new KeyValue() .setTopLabel("Build No.") .setContent(buildState.getNumber()) - .setBottomLabel("Failed") + .setBottomLabel(status) .setButton(linkButton("Build", Urls.urlOfSpec("https://google.com"))); return new WidgetMarkup().setKeyValue(keyValue); } @@ -139,6 +153,7 @@ private static OnClick openLink(Url url) { } private static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { + Validate.checkValid(buildState); var cardHeader = new CardHeader() .setTitle(buildState.getRepositorySlug()) .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); @@ -168,6 +183,7 @@ public static void main(String[] args) { .newBuilder() .setRepositorySlug("SpineEventEngine/base") .setNumber("5292") + .setStatus(BuildState.Status.FAILING) .setLastCommit(commit) .setTravisCiUrl(Urls.urlOfSpec( "https://travis-ci.com/github/SpineEventEngine/base/builds/166723382")) From 900c150127768f41d9ca61cfa3395293e6f99835 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:12:07 +0300 Subject: [PATCH 039/492] Set thread name if it is *not* empty --- .../main/java/io/spine/chatbot/api/GoogleChatClient.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index bd192dae..4112afea 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -37,7 +37,6 @@ import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; -import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.BuildState; @@ -52,6 +51,8 @@ import java.security.GeneralSecurityException; import java.util.List; +import static com.google.common.base.Strings.isNullOrEmpty; + public final class GoogleChatClient { private static final String BOT_NAME = "Spine Chat Bot"; @@ -161,9 +162,8 @@ private static Message buildStateMessage(BuildState buildState, @Nullable String sectionWithWidget(buildStateWidget(buildState)), sectionWithWidget(commitWidget(buildState.getLastCommit())) ); - var message = new Message() - .setCards(cardWith(cardHeader, sections)); - if (Strings.isNullOrEmpty(threadName)) { + var message = new Message().setCards(cardWith(cardHeader, sections)); + if (!isNullOrEmpty(threadName)) { message.setThread(new Thread().setName(threadName)); } return message; From 59c5d4c2407d205cfb128b5f25e5bb90cd344eea Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:16:42 +0300 Subject: [PATCH 040/492] Add commit time and try with long message --- .../main/java/io/spine/chatbot/api/GoogleChatClient.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 4112afea..4a36b1a5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -114,9 +114,9 @@ private static Section sectionWithWidget(WidgetMarkup widget) { private static WidgetMarkup commitWidget(BuildState.Commit commit) { var keyValue = new KeyValue() - .setTopLabel("Commit") + .setTopLabel("Commit " + commit.getSha()) .setContent(commit.getMessage()) - .setBottomLabel(commit.getSha()) + .setBottomLabel("At " + commit.getCommittedAt()) .setButton(linkButton("Changes", commit.getCompareUrl())); return new WidgetMarkup().setKeyValue(keyValue); } @@ -174,7 +174,9 @@ public static void main(String[] args) { listSpaces(chat).forEach(System.out::println); var commit = BuildState.Commit .newBuilder() - .setMessage("My test commit") + .setCommittedAt("2020-06-03T14:45:02Z") + .setMessage( + "My test commit with a very long description and even\n\n Sub-description, cause it is very relevant and has additional reference to issue\n #749 and a lot of kind words!") .setSha("d97c603d5e855d0d211382f78916ad085ba04743") .setCompareUrl(Urls.urlOfSpec( "https://github.com/SpineEventEngine/base/commit/d97c603d5e855d0d211382f78916ad085ba04743")) From a2e799416ed32f80deb8a1b55815baf6c7a3250a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:19:30 +0300 Subject: [PATCH 041/492] Use sections for build state and commit --- .../io/spine/chatbot/api/GoogleChatClient.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 4a36b1a5..3a8cd2cf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -112,6 +112,10 @@ private static Section sectionWithWidget(WidgetMarkup widget) { return new Section().setWidgets(List.of(widget)); } + private static Section commitSection(BuildState.Commit commit) { + return sectionWithWidget(commitWidget(commit)); + } + private static WidgetMarkup commitWidget(BuildState.Commit commit) { var keyValue = new KeyValue() .setTopLabel("Commit " + commit.getSha()) @@ -121,8 +125,12 @@ private static WidgetMarkup commitWidget(BuildState.Commit commit) { return new WidgetMarkup().setKeyValue(keyValue); } + private static Section buildStateSection(BuildState buildState) { + return sectionWithWidget(buildStateWidget(buildState)); + } + private static WidgetMarkup buildStateWidget(BuildState buildState) { - String status = null; + String status; switch (buildState.getStatus()) { case PASSING: status = "Passing"; @@ -159,8 +167,8 @@ private static Message buildStateMessage(BuildState buildState, @Nullable String .setTitle(buildState.getRepositorySlug()) .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); var sections = ImmutableList.of( - sectionWithWidget(buildStateWidget(buildState)), - sectionWithWidget(commitWidget(buildState.getLastCommit())) + buildStateSection(buildState), + commitSection(buildState.getLastCommit()) ); var message = new Message().setCards(cardWith(cardHeader, sections)); if (!isNullOrEmpty(threadName)) { From 682732a4f00e5045a04ff2fe13e9fbe2a39afd5f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:54:16 +0300 Subject: [PATCH 042/492] Add commit author info --- .../main/java/io/spine/chatbot/api/TravisClient.java | 3 ++- .../main/proto/spine/chatbot/github/repository.proto | 3 +++ .../src/main/proto/spine/chatbot/travis/travis.proto | 10 ++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index a5f5dc01..b7bd2c75 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -47,7 +47,8 @@ private TravisClient(String token) { public BuildsResponse queryBuildsFor(String repoSlug) { var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); - var repoBuilds = "/repo/" + encodedSlug + "/builds?limit=1&branch.name=master"; + var repoBuilds = + "/repo/" + encodedSlug + "/builds?limit=1&branch.name=master?include=build.commit"; var request = apiRequest(repoBuilds, apiToken); try { var result = CLIENT.send(request, jsonBodyHandler(BuildsResponse.class)); diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 14acb209..34388ccb 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -101,6 +101,9 @@ message BuildState { // Commit date from git. string committed_at = 4; + + // Commit author from git. + string authored_by = 5; } // The repository slug the builds is associated with. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 4b9ff541..c7a097b4 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -80,6 +80,16 @@ message Commit { // Commit date from git. string committed_at = 6; + + // Commit author. + Author author = 7; + + // Git commit author information + message Author { + + // Git name of the commit author + string name = 1; + } } // Minimal Travis CI build representation. From 9b3ace953ca4240d5c6cfcdb307080a50603d41a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 13:55:11 +0300 Subject: [PATCH 043/492] Use text paragraph widgets instead of KeyValue for commit info. Move actions to a separate section --- .../spine/chatbot/api/GoogleChatClient.java | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 3a8cd2cf..ac7be1b6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -33,6 +33,7 @@ import com.google.api.services.chat.v1.model.Section; import com.google.api.services.chat.v1.model.Space; import com.google.api.services.chat.v1.model.TextButton; +import com.google.api.services.chat.v1.model.TextParagraph; import com.google.api.services.chat.v1.model.Thread; import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.auth.http.HttpCredentialsAdapter; @@ -113,16 +114,29 @@ private static Section sectionWithWidget(WidgetMarkup widget) { } private static Section commitSection(BuildState.Commit commit) { - return sectionWithWidget(commitWidget(commit)); + var commitInfo = String.format( + "Authored by %s at %s.", commit.getAuthoredBy(), commit.getCommittedAt() + ); + var section = new Section() + .setHeader("Commit " + commit.getSha()) + .setWidgets(ImmutableList.of( + textParagraph(commit.getMessage()), + textParagraph(commitInfo) + )); + return section; } - private static WidgetMarkup commitWidget(BuildState.Commit commit) { - var keyValue = new KeyValue() - .setTopLabel("Commit " + commit.getSha()) - .setContent(commit.getMessage()) - .setBottomLabel("At " + commit.getCommittedAt()) - .setButton(linkButton("Changes", commit.getCompareUrl())); - return new WidgetMarkup().setKeyValue(keyValue); + private static Section actions(BuildState buildState) { + BuildState.Commit commit = buildState.getLastCommit(); + WidgetMarkup actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( + linkButton("Open build", buildState.getTravisCiUrl()), + linkButton("Open changeset", commit.getCompareUrl()) + )); + return sectionWithWidget(actionButtons); + } + + private static WidgetMarkup textParagraph(String formattedText) { + return new WidgetMarkup().setTextParagraph(new TextParagraph().setText(formattedText)); } private static Section buildStateSection(BuildState buildState) { @@ -146,8 +160,7 @@ private static WidgetMarkup buildStateWidget(BuildState buildState) { var keyValue = new KeyValue() .setTopLabel("Build No.") .setContent(buildState.getNumber()) - .setBottomLabel(status) - .setButton(linkButton("Build", Urls.urlOfSpec("https://google.com"))); + .setBottomLabel(status); return new WidgetMarkup().setKeyValue(keyValue); } @@ -168,7 +181,8 @@ private static Message buildStateMessage(BuildState buildState, @Nullable String .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); var sections = ImmutableList.of( buildStateSection(buildState), - commitSection(buildState.getLastCommit()) + commitSection(buildState.getLastCommit()), + actions(buildState) ); var message = new Message().setCards(cardWith(cardHeader, sections)); if (!isNullOrEmpty(threadName)) { @@ -188,6 +202,7 @@ public static void main(String[] args) { .setSha("d97c603d5e855d0d211382f78916ad085ba04743") .setCompareUrl(Urls.urlOfSpec( "https://github.com/SpineEventEngine/base/commit/d97c603d5e855d0d211382f78916ad085ba04743")) + .setAuthoredBy("yuri-sergiichuk") .vBuild(); BuildState buildState = BuildState .newBuilder() From 89a362d46f7cc5453ddde6adc4157b3e4ab2c20e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 15:35:36 +0300 Subject: [PATCH 044/492] Drop receiver module --- build.gradle | 2 - settings.gradle | 1 - webhook-receiver/build.gradle | 25 -------- .../github/webhook/receiver/Application.java | 30 --------- .../github/webhook/receiver/Receiver.java | 33 ---------- .../src/main/resources/application.yml | 23 ------- .../src/main/resources/log4j2.xml | 35 ---------- .../github/webhook/receiver/ReceiverTest.java | 64 ------------------- 8 files changed, 213 deletions(-) delete mode 100644 webhook-receiver/build.gradle delete mode 100644 webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java delete mode 100644 webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java delete mode 100644 webhook-receiver/src/main/resources/application.yml delete mode 100644 webhook-receiver/src/main/resources/log4j2.xml delete mode 100644 webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java diff --git a/build.gradle b/build.gradle index e6b7249a..cac1b9bf 100644 --- a/build.gradle +++ b/build.gradle @@ -83,8 +83,6 @@ subprojects { test.classpath += configurations.developmentOnly - mainClassName = "io.spine.chatbot.Application" - test { useJUnitPlatform() } diff --git a/settings.gradle b/settings.gradle index 879fc013..3cab8db6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,6 +19,5 @@ */ rootProject.name = "chat-bot" -include 'webhook-receiver' include 'google-chat-bot' diff --git a/webhook-receiver/build.gradle b/webhook-receiver/build.gradle deleted file mode 100644 index 6094714a..00000000 --- a/webhook-receiver/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -jib { - to { - image = "gcr.io/${gcpProject}/github-webhook-receiver" - } -} diff --git a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java deleted file mode 100644 index 7bea0834..00000000 --- a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Application.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.github.webhook.receiver; - -import io.micronaut.runtime.Micronaut; - -public class Application { - - public static void main(String[] args) { - Micronaut.run(Application.class, args); - } -} diff --git a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java b/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java deleted file mode 100644 index a48d515e..00000000 --- a/webhook-receiver/src/main/java/io/spine/github/webhook/receiver/Receiver.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.github.webhook.receiver; - -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Get; - -@Controller("/web-hook") -public class Receiver { - - @Get(uri = "/", produces = "text/plain") - public String process() { - return "OK"; - } -} \ No newline at end of file diff --git a/webhook-receiver/src/main/resources/application.yml b/webhook-receiver/src/main/resources/application.yml deleted file mode 100644 index cfaba24b..00000000 --- a/webhook-receiver/src/main/resources/application.yml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright 2020, TeamDev. All rights reserved. -# -# Redistribution and use in source and/or binary forms, with or without -# modification, must retain the above copyright notice and the following -# disclaimer. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -micronaut: - application: - name: webhookReceiver diff --git a/webhook-receiver/src/main/resources/log4j2.xml b/webhook-receiver/src/main/resources/log4j2.xml deleted file mode 100644 index b1ea1984..00000000 --- a/webhook-receiver/src/main/resources/log4j2.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java b/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java deleted file mode 100644 index ef75dde9..00000000 --- a/webhook-receiver/src/test/java/io/spine/github/webhook/receiver/ReceiverTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.github.webhook.receiver; - -import io.micronaut.context.ApplicationContext; -import io.micronaut.http.HttpRequest; -import io.micronaut.http.client.HttpClient; -import io.micronaut.runtime.server.EmbeddedServer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@DisplayName("Receiver should") -final class ReceiverTest { - - private static EmbeddedServer server; - private static HttpClient client; - - @BeforeAll - public static void setupServer() { - server = ApplicationContext.run(EmbeddedServer.class); - client = server - .getApplicationContext() - .createBean(HttpClient.class, server.getURL()); - } - - @AfterAll - public static void stopServer() { - if (server != null) { - server.stop(); - } - if (client != null) { - client.stop(); - } - } - - @Test - void processIncomingWebHook() { - String actual = client.toBlocking() - .retrieve(HttpRequest.GET("/web-hook")); - assertEquals("OK", actual); - } -} From b81d21b8f1c8c0fb51d25ef213565d3ede70cfd1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 15:35:48 +0300 Subject: [PATCH 045/492] Define main class --- google-chat-bot/build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 638a7f53..58de0550 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -33,8 +33,13 @@ dependencies { testImplementation "io.spine:spine-testutil-server:${spine.version()}" } +mainClassName = "io.spine.chatbot.Application" + jib { to { - image = "gcr.io/${gcpProject}/chat-bot" + image = "gcr.io/${gcpProject}/google-chat-bot-server" + } + container { + mainClass = mainClassName } } From e4b1ee354377e0e347aa171037f4d5b462ab2513 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 15:35:59 +0300 Subject: [PATCH 046/492] Create stub CRON controller --- .../java/io/spine/chatbot/CronController.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/CronController.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java new file mode 100644 index 00000000..8edc0848 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Post; +import io.spine.chatbot.github.organization.Organization; +import io.spine.client.Client; + +import java.util.stream.Collectors; + +import static io.spine.chatbot.Application.SERVER_NAME; + +@Controller("/cron") +public class CronController { + + @Post("/repositories/check") + public String checkRepositoryStatuses() { + Client client = Client + .inProcess(SERVER_NAME) + .build(); + String result = client.asGuest() + .select(Organization.class) + .run() + .stream() + .map(String::valueOf) + .collect(Collectors.joining()); + return "success"; + } +} From 47543389a2cb27a74668909933ebee163dcc7088 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 16:37:56 +0300 Subject: [PATCH 047/492] Use `string` for build state as we're receiving string value from Travis --- .../io/spine/chatbot/api/GoogleChatClient.java | 17 ++--------------- .../proto/spine/chatbot/github/repository.proto | 12 ++---------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index ac7be1b6..b5428d5b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -144,23 +144,10 @@ private static Section buildStateSection(BuildState buildState) { } private static WidgetMarkup buildStateWidget(BuildState buildState) { - String status; - switch (buildState.getStatus()) { - case PASSING: - status = "Passing"; - break; - case FAILING: - status = "Failing"; - break; - case BS_STATUS_UNKNOWN: - case UNRECOGNIZED: - default: - status = "Undefined status"; - } var keyValue = new KeyValue() .setTopLabel("Build No.") .setContent(buildState.getNumber()) - .setBottomLabel(status); + .setBottomLabel(buildState.getState()); return new WidgetMarkup().setKeyValue(keyValue); } @@ -208,7 +195,7 @@ public static void main(String[] args) { .newBuilder() .setRepositorySlug("SpineEventEngine/base") .setNumber("5292") - .setStatus(BuildState.Status.FAILING) + .setState("failed") .setLastCommit(commit) .setTravisCiUrl(Urls.urlOfSpec( "https://travis-ci.com/github/SpineEventEngine/base/builds/166723382")) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 34388ccb..9935bddf 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -66,22 +66,14 @@ message BuildState { spine.net.Url travis_ci_url = 2; // Current state of the build. - Status status = 3; + string state = 3; // State of the previous build. - Status previous_status = 4; + string previous_state = 4; // The branch the build is associated with. string branch = 5; - enum Status { - BS_STATUS_UNKNOWN = 0; - - PASSING = 1; - - FAILING = 2; - } - // The commit the build is associated with. Commit last_commit = 6; From eac6a4ad06842964fcdd80aae025fd9cb7cbfb5e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 16:42:43 +0300 Subject: [PATCH 048/492] Add RepositoryBuild process --- .../chatbot/server/github/GitHubContext.java | 1 + .../server/github/RepositoryBuildProcess.java | 84 +++++++++++++++++++ .../chatbot/github/repository_build.proto | 46 ++++++++++ .../github/repository_build_commands.proto | 40 +++++++++ 4 files changed, 171 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 61cac5fa..82463653 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -85,6 +85,7 @@ public static BoundedContextBuilder newBuilder() { .singleTenant(NAME) .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) + .add(RepositoryBuildProcess.class) .add(new OrganizationRepositoriesRepository()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java new file mode 100644 index 00000000..809a8608 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -0,0 +1,84 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.BuildState; +import io.spine.chatbot.github.repository.build.RepositoryBuild; +import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; +import io.spine.chatbot.github.repository.command.SetBuildState; +import io.spine.chatbot.travis.Build; +import io.spine.chatbot.travis.Commit; +import io.spine.net.Urls; +import io.spine.server.command.Command; +import io.spine.server.procman.ProcessManager; + +final class RepositoryBuildProcess + extends ProcessManager { + + @Command + SetBuildState handle(CheckRepositoryBuild c) { + var travis = new TravisClient(""); + var builds = travis.queryBuildsFor(id().getValue()) + .getBuildsList(); + if (builds.isEmpty()) { + throw new RuntimeException("No builds available for repository " + idAsString()); + } + var build = builds.get(0); + var buildState = from(build); + return SetBuildState + .newBuilder() + .setId(c.getId()) + .setBuildState(buildState) + .vBuild(); + } + + private static BuildState from(Build build) { + var slug = build.getRepository() + .getSlug(); + var spec = String.format("https://travis-ci.com/github/%s/builds/%d", slug, build.getId()); + return BuildState + .newBuilder() + .setState(build.getState()) + .setPreviousState(build.getPreviousState()) + .setBranch(build.getBranch() + .getName()) + .setLastCommit(from(build.getCommit())) + .setCreatedBy(build.getCreatedBy() + .getLogin()) + .setRepositorySlug(slug) + .setTravisCiUrl(Urls.urlOfSpec(spec)) + .vBuild(); + } + + private static BuildState.Commit from(Commit commit) { + return BuildState.Commit + .newBuilder() + .setSha(commit.getSha()) + .setMessage(commit.getMessage()) + .setCommittedAt(commit.getCommittedAt()) + .setAuthoredBy(commit.getAuthor() + .getName()) + .setCompareUrl(Urls.urlOfSpec(commit.getCompareUrl())) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto new file mode 100644 index 00000000..80a5f1f5 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -0,0 +1,46 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.repository.build"; +option java_outer_classname = "RepositoryBuildProto"; +option java_multiple_files = true; + + +import "google/protobuf/timestamp.proto"; + +import "spine/chatbot/github/identifiers.proto"; + +// A GitHub repository build process. +message RepositoryBuild { + option (entity).kind = PROCESS_MANAGER; + option (entity).visibility = FULL; + + RepositoryId id = 1; + + // Time of the last status check. + google.protobuf.Timestamp last_status_check = 2; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto new file mode 100644 index 00000000..00387711 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -0,0 +1,40 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.repository.build.command"; +option java_outer_classname = "RepositoryBuildCommandsProto"; +option java_multiple_files = true; + + +import "spine/chatbot/github/identifiers.proto"; + +// Requests a check of the repository CI build. +message CheckRepositoryBuild { + + // ID of the repository to perform a check for. + RepositoryId id = 1; +} From 7b140b20dbcdbe83dd044dfc8e528f2fb1b308e0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 4 Jun 2020 16:50:02 +0300 Subject: [PATCH 049/492] List repositories for all organizations --- .../java/io/spine/chatbot/CronController.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java index 8edc0848..631ee629 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java @@ -23,8 +23,10 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; import io.spine.chatbot.github.organization.Organization; +import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.client.Client; +import java.util.Collection; import java.util.stream.Collectors; import static io.spine.chatbot.Application.SERVER_NAME; @@ -37,12 +39,21 @@ public String checkRepositoryStatuses() { Client client = Client .inProcess(SERVER_NAME) .build(); - String result = client.asGuest() - .select(Organization.class) - .run() - .stream() - .map(String::valueOf) - .collect(Collectors.joining()); + var orgIds = client.asGuest() + .select(Organization.class) + .run() + .stream() + .map(Organization::getId) + .collect(Collectors.toList()); + var orgRepos = client.asGuest() + .select(OrganizationRepositories.class) + .byId(orgIds) + .run(); + var repositoryIds = orgRepos.stream() + .map(OrganizationRepositories::getRepositoriesList) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + return "success"; } } From 3559422f211a23bfcbf686704db9725bdd336d64 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 5 Jun 2020 14:24:35 +0300 Subject: [PATCH 050/492] Define Google Chat protos --- .../chatbot/google/chat/chat_events.proto | 44 +++++++++++++++ .../chatbot/google/chat/identifiers.proto | 17 +++--- .../spine/chatbot/google/chat/thread.proto | 49 +++++++++++++++++ .../chatbot/google/chat/thread_chat.proto | 46 ++++++++++++++++ .../chatbot/google/chat/thread_commands.proto | 44 +++++++++++++++ .../chatbot/google/chat/thread_events.proto | 53 +++++++++++++++++++ 6 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto new file mode 100644 index 00000000..19197142 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -0,0 +1,44 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.event"; +option java_outer_classname = "ChatEventsProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +// Denotes that a message was created in the space. +message MessageCreated { + + MessageId id = 1 [(required) = true]; + + // ID of the space within which the message is created. + SpaceId space_id = 2 [(required) = true]; + + // ID of the thread within which the message is created if created in a threaded space. + ThreadId thread_id = 3; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto index ffd6eeca..1aa3d945 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -32,18 +32,23 @@ option java_multiple_files = true; // Hangouts Chat Space identifier. message SpaceId { - // Resource name of the space, in the form "spaces/*". + // Resource name of the space, in the form `spaces/`. string value = 1 [(required) = true]; } -// Hangouts Chat Room identifier. -message RoomId { +// Hangouts Chat Room Thread identifier. +message ThreadId { + // The thread identifier is linked to the topic discussed in the thread. + // + // E.g. if the thread is denoted to the build status of a GitHub repository, + // the GitHub repository slug could be used as the thread ID. string value = 1 [(required) = true]; } -// Hangout Chat Room Thread identifier. -message ThreadId { +// Hangouts Chat Message identifier. +message MessageId { - string uuid = 1 [(required) = true]; + // Resource name of the message, in the form `spaces//messages/`. + string value = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto new file mode 100644 index 00000000..57e7d0d0 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -0,0 +1,49 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.thread"; +option java_outer_classname = "ThreadProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +// A thread in Google Chat room. +message Thread { + option (entity).kind = AGGREGATE; + option (entity).visibility = FULL; + + ThreadId id = 1; + + // Resource name of the thread, in the form `spaces//threads/`. + string name = 2; + + // ID of the space within with the thread is available. + SpaceId space_id = 3; + + // IDs of the messages posted by the bot to the thread. + repeated MessageId messages = 4; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto new file mode 100644 index 00000000..3d1eadc7 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -0,0 +1,46 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.thread"; +option java_outer_classname = "ThreadChatProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +// A thread in Google Chat room. +message ThreadChat { + option (entity).kind = PROCESS_MANAGER; + option (entity).visibility = FULL; + + ThreadId id = 1; + + // Resource name of the thread, in the form `spaces//threads/**`. + string name = 2; + + // ID of the space within with the thread is available. + SpaceId space_id = 3; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto new file mode 100644 index 00000000..4357bce9 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto @@ -0,0 +1,44 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.thread.command"; +option java_outer_classname = "ThreadCommandsProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +// Denotes that a message was created in the space. +message InitializeThread { + + ThreadId id = 1; + + // Resource name of the thread, in the form `spaces//threads/`. + string name = 2; + + // ID of the space within with the thread is available. + SpaceId space_id = 3; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto new file mode 100644 index 00000000..4c0fb920 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -0,0 +1,53 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.thread.event"; +option java_outer_classname = "ThreadEventsProto"; +option java_multiple_files = true; + +import "spine/chatbot/google/chat/identifiers.proto"; + +// Denotes that a message was created in the space. +message ThreadInitialized { + + ThreadId id = 1; + + // Resource name of the thread, in the form `spaces//threads/`. + string name = 2; + + // ID of the space within with the thread is available. + SpaceId space_id = 3; +} + +// Denotes that a message was created in the space. +message MessageAdded { + + MessageId id = 1 [(required) = true]; + + // ID of the thread to which the message is added. + ThreadId thread_id = 2 [(required) = true]; +} From 9de0525fd448416037b65273f2e760ec4e08b21d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 11:37:43 +0300 Subject: [PATCH 051/492] Add chat space to organization --- .../io/spine/chatbot/server/github/OrganizationAggregate.java | 4 +++- .../src/main/proto/spine/chatbot/github/organization.proto | 3 +++ .../proto/spine/chatbot/github/organization_commands.proto | 3 +++ .../main/proto/spine/chatbot/github/organization_events.proto | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 195de772..66500fef 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -40,6 +40,7 @@ OrganizationRegistered handle(RegisterOrganization c) { .setName(c.getName()) .setTravisCiUrl(c.getTravisCiUrl()) .setWebsiteUrl(c.getWebsiteUrl()) + .setGoogleChatSpace(c.getGoogleChatSpace()) .vBuild(); } @@ -48,6 +49,7 @@ private void on(OrganizationRegistered e) { builder().setName(e.getName()) .setGithubUrl(e.getGithubUrl()) .setTravisCiUrl(e.getTravisCiUrl()) - .setWebsiteUrl(e.getWebsiteUrl()); + .setWebsiteUrl(e.getWebsiteUrl()) + .setGoogleChatSpace(e.getGoogleChatSpace()); } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index 38e81bca..ed6cd6b7 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -51,4 +51,7 @@ message Organization { // URL of the organization Travis CI profile. spine.net.Url travis_ci_url = 5; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 6; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 040bf16c..7fac6b87 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -48,4 +48,7 @@ message RegisterOrganization { // URL of the organization Travis CI profile. spine.net.Url travis_ci_url = 5 [(required) = true]; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 6 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index 378c8020..4dbb2ecd 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -48,4 +48,7 @@ message OrganizationRegistered { // URL of the organization Travis CI profile. spine.net.Url travis_ci_url = 5 [(required) = true]; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 6 [(required) = true]; } From ee1aa3a6f2381ee85094ed4215f9b5211a458cdc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 11:38:47 +0300 Subject: [PATCH 052/492] Move build state to RepositoryBuild process --- .../server/github/RepositoryAggregate.java | 24 ------- .../server/github/RepositoryBuildProcess.java | 23 +++++-- .../spine/chatbot/github/repository.proto | 59 ----------------- .../chatbot/github/repository_build.proto | 64 +++++++++++++++++++ .../github/repository_build_events.proto | 42 ++++++++++++ .../chatbot/github/repository_commands.proto | 11 +--- .../chatbot/github/repository_events.proto | 9 --- 7 files changed, 123 insertions(+), 109 deletions(-) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java index 8817f035..58b47f88 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -21,11 +21,8 @@ package io.spine.chatbot.server.github; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.repository.BuildStateChange; import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; -import io.spine.chatbot.github.repository.command.SetBuildState; -import io.spine.chatbot.github.repository.event.BuildStateChanged; import io.spine.chatbot.github.repository.event.RepositoryRegistered; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; @@ -52,25 +49,4 @@ private void on(RepositoryRegistered e) { .setGithubUrl(e.getGithubUrl()) .setTravisCiUrl(e.getTravisCiUrl()); } - - @Assign - BuildStateChanged handle(SetBuildState c) { - var stateChange = BuildStateChange - .newBuilder() - .setPreviousValue(state().getBuildState()) - .setNewValue(c.getBuildState()) - .vBuild(); - var result = BuildStateChanged - .newBuilder() - .setId(c.getId()) - .setChange(stateChange) - .vBuild(); - return result; - } - - @Apply - private void on(BuildStateChanged e) { - builder().setBuildState(e.getChange() - .getNewValue()); - } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index 809a8608..b427d2df 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -20,23 +20,25 @@ package io.spine.chatbot.server.github; +import io.spine.base.Time; import io.spine.chatbot.api.TravisClient; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.repository.BuildState; +import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; -import io.spine.chatbot.github.repository.command.SetBuildState; +import io.spine.chatbot.github.repository.build.event.BuildStateChanged; import io.spine.chatbot.travis.Build; import io.spine.chatbot.travis.Commit; import io.spine.net.Urls; -import io.spine.server.command.Command; +import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; final class RepositoryBuildProcess extends ProcessManager { - @Command - SetBuildState handle(CheckRepositoryBuild c) { + @Assign + BuildStateChanged handle(CheckRepositoryBuild c) { var travis = new TravisClient(""); var builds = travis.queryBuildsFor(id().getValue()) .getBuildsList(); @@ -45,10 +47,17 @@ SetBuildState handle(CheckRepositoryBuild c) { } var build = builds.get(0); var buildState = from(build); - return SetBuildState + builder().setLastStatusCheck(Time.currentTime()) + .setBuildState(buildState); + var stateChange = BuildStateChange + .newBuilder() + .setPreviousValue(state().getBuildState()) + .setNewValue(buildState) + .vBuild(); + return BuildStateChanged .newBuilder() .setId(c.getId()) - .setBuildState(buildState) + .setChange(stateChange) .vBuild(); } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 9935bddf..74be5b85 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -51,63 +51,4 @@ message Repository { // ID of the organization repository is related to if any. OrganizationId organization_id = 5; - - // Current state of the build. - BuildState build_state = 6; -} - -// State of the build for a repository branch. -message BuildState { - - // Incremental number for a repository's builds. - string number = 1; - - // Travis CI URL of the build. - spine.net.Url travis_ci_url = 2; - - // Current state of the build. - string state = 3; - - // State of the previous build. - string previous_state = 4; - - // The branch the build is associated with. - string branch = 5; - - // The commit the build is associated with. - Commit last_commit = 6; - - // The User or Organization that created the build. - string created_by = 7; - - message Commit { - - // Checksum the commit has in git and is identified by. - string sha = 1; - - // Commit message. - string message = 2; - - // URL to the commit's diff on GitHub. - spine.net.Url compare_url = 3; - - // Commit date from git. - string committed_at = 4; - - // Commit author from git. - string authored_by = 5; - } - - // The repository slug the builds is associated with. - string repository_slug = 8; -} - -// Definition of a change in a `build_state` field. -message BuildStateChange { - - // The value of the field that's changing. - BuildState previous_value = 1; - - // The new value of the field. - BuildState new_value = 2 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 80a5f1f5..8d2de708 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -32,6 +32,8 @@ option java_multiple_files = true; import "google/protobuf/timestamp.proto"; +import "spine/net/url.proto"; + import "spine/chatbot/github/identifiers.proto"; // A GitHub repository build process. @@ -43,4 +45,66 @@ message RepositoryBuild { // Time of the last status check. google.protobuf.Timestamp last_status_check = 2; + + // Current state of the build. + BuildState build_state = 3; +} + +// State of the build for a repository branch. +message BuildState { + + // Incremental number for a repository's builds. + string number = 1; + + // Travis CI URL of the build. + spine.net.Url travis_ci_url = 2; + + // Current state of the build. + string state = 3; + + // State of the previous build. + string previous_state = 4; + + // The branch the build is associated with. + string branch = 5; + + // The commit the build is associated with. + Commit last_commit = 6; + + // The User or Organization that created the build. + string created_by = 7; + + message Commit { + + // Checksum the commit has in git and is identified by. + string sha = 1; + + // Commit message. + string message = 2; + + // URL to the commit's diff on GitHub. + spine.net.Url compare_url = 3; + + // Commit date from git. + string committed_at = 4; + + // Commit author from git. + string authored_by = 5; + } + + // The repository slug the builds is associated with. + string repository_slug = 8; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 9; +} + +// Definition of a change in a `build_state` field. +message BuildStateChange { + + // The value of the field that's changing. + BuildState previous_value = 1; + + // The new value of the field. + BuildState new_value = 2 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto new file mode 100644 index 00000000..96c651d4 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.repository.build.event"; +option java_outer_classname = "RepositoryBuildEventsProto"; +option java_multiple_files = true; + + +import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/repository_build.proto"; + +// Denotes that a build state was changed. +message BuildStateChanged { + + RepositoryId id = 1 [(required) = true]; + + BuildStateChange change = 2; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index cc9578d5..7e8742de 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -32,7 +32,6 @@ option java_multiple_files = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; -import "spine/chatbot/github/repository.proto"; // Registers a new repository in the system. message RegisterRepository { @@ -50,12 +49,4 @@ message RegisterRepository { // ID of the organization repository is related to if any. OrganizationId organization_id = 5; -} - -// Sets the new build state of the repository. -message SetBuildState { - - RepositoryId id = 1 [(required) = true]; - - BuildState build_state = 2; -} +} \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 2bdfaf11..eab4abd6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -32,7 +32,6 @@ option java_multiple_files = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; -import "spine/chatbot/github/repository.proto"; // Denotes that a new repository is registered. message RepositoryRegistered { @@ -51,11 +50,3 @@ message RepositoryRegistered { // ID of the organization repository is related to if any. OrganizationId organization_id = 5; } - -// Denotes that a build state was changed. -message BuildStateChanged { - - RepositoryId id = 1 [(required) = true]; - - BuildStateChange change = 2; -} From 4a748eb638894af3152beff1a02e2edaaf2df223 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 11:39:09 +0300 Subject: [PATCH 053/492] Remove Space `name` field as it is the same as the ID value --- .../io/spine/chatbot/server/google/chat/SpaceAggregate.java | 3 +-- .../src/main/proto/spine/chatbot/google/chat/space.proto | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 025b3e28..31901319 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -45,8 +45,7 @@ SpaceRegistered handle(RegisterSpace c) { @Apply private void on(SpaceRegistered e) { - builder().setName(e.getName()) - .setDisplayName(e.getDisplayName()) + builder().setDisplayName(e.getDisplayName()) .setSingleUserBotDm(e.getSingleUserBotDm()) .setThreaded(e.getThreaded()); } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 7c04e34a..e84752e4 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -38,9 +38,6 @@ message Space { SpaceId id = 1; - // Resource name of the space, in the form "spaces/*". - string name = 2; - // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; From 7e8babd8ed9d800b069a96137e037362ad7a4297 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 11:40:03 +0300 Subject: [PATCH 054/492] Integrate GoogleChatClient into ThreadChat process --- .../spine/chatbot/api/GoogleChatClient.java | 11 ++- .../server/google/chat/Identifiers.java | 66 +++++++++++++++++ .../server/google/chat/ThreadAggregate.java | 64 +++++++++++++++++ .../server/google/chat/ThreadChatProcess.java | 71 +++++++++++++++++++ .../chatbot/google/chat/chat_events.proto | 12 ++++ .../chatbot/google/chat/thread_commands.proto | 44 ------------ 6 files changed, 221 insertions(+), 47 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java delete mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index b5428d5b..23467375 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -40,7 +40,7 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.spine.chatbot.github.repository.BuildState; +import io.spine.chatbot.github.repository.build.BuildState; import io.spine.net.Url; import io.spine.net.Urls; import io.spine.validate.Validate; @@ -92,6 +92,11 @@ private static List listSpaces(HangoutsChat chat) { } } + public static Message sendMessage(BuildState buildState, @Nullable String threadName) { + var message = buildStateMessage(buildState, threadName); + return sendMessage(hangoutsChat(), buildState.getGoogleChatSpace(), message); + } + @CanIgnoreReturnValue private static Message sendMessage(HangoutsChat chat, String space, Message message) { try { @@ -201,8 +206,8 @@ public static void main(String[] args) { "https://travis-ci.com/github/SpineEventEngine/base/builds/166723382")) .setBranch("master") .setCreatedBy("yuri-sergiichuk") + .setGoogleChatSpace("spaces/AAAAnLxnh_o") .vBuild(); - Message message = buildStateMessage(buildState, "spaces/AAAAnLxnh_o/threads/TPFMA4dK0_4"); - sendMessage(chat, "spaces/AAAAnLxnh_o", message); + System.out.println(sendMessage(buildState, "spaces/AAAAnLxnh_o/threads/TPFMA4dK0_4")); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java new file mode 100644 index 00000000..232e3d27 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java @@ -0,0 +1,66 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.MessageId; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.ThreadId; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An utility for working with {@link GoogleChatContext} identifiers. + */ +public final class Identifiers { + + /** + * Prevents instantiation of this utility class. + */ + private Identifiers() { + } + + /** Creates a new {@link ThreadId} out of the specified {@code value}. **/ + public static ThreadId newThreadId(String value) { + checkNotNull(value); + return ThreadId + .newBuilder() + .setValue(value) + .vBuild(); + } + + /** Creates a new {@link SpaceId} out of the specified {@code value}. **/ + public static SpaceId newSpaceId(String value) { + checkNotNull(value); + return SpaceId + .newBuilder() + .setValue(value) + .vBuild(); + } + + /** Creates a new {@link MessageId} out of the specified {@code value}. **/ + public static MessageId newMessageId(String value) { + checkNotNull(value); + return MessageId + .newBuilder() + .setValue(value) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java new file mode 100644 index 00000000..581dce2c --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -0,0 +1,64 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.ThreadId; +import io.spine.chatbot.google.chat.event.MessageCreated; +import io.spine.chatbot.google.chat.event.ThreadCreated; +import io.spine.chatbot.google.chat.thread.Thread; +import io.spine.chatbot.google.chat.thread.event.MessageAdded; +import io.spine.chatbot.google.chat.thread.event.ThreadInitialized; +import io.spine.server.aggregate.Aggregate; +import io.spine.server.aggregate.Apply; +import io.spine.server.event.React; + +final class ThreadAggregate extends Aggregate { + + @React + ThreadInitialized on(ThreadCreated e) { + return ThreadInitialized + .newBuilder() + .setId(e.getId()) + .setName(e.getName()) + .setSpaceId(e.getSpaceId()) + .vBuild(); + } + + @Apply + private void on(ThreadInitialized e) { + builder().setName(e.getName()) + .setSpaceId(e.getSpaceId()); + } + + @React + MessageAdded on(MessageCreated e) { + return MessageAdded + .newBuilder() + .setId(e.getId()) + .setThreadId(e.getThreadId()) + .vBuild(); + } + + @Apply + private void on(MessageAdded e) { + builder().addMessages(e.getId()); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java new file mode 100644 index 00000000..a9352379 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -0,0 +1,71 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import com.google.common.base.Strings; +import io.spine.chatbot.api.GoogleChatClient; +import io.spine.chatbot.github.repository.build.event.BuildStateChanged; +import io.spine.chatbot.google.chat.ThreadId; +import io.spine.chatbot.google.chat.event.MessageCreated; +import io.spine.chatbot.google.chat.event.ThreadCreated; +import io.spine.chatbot.google.chat.thread.ThreadChat; +import io.spine.server.event.React; +import io.spine.server.procman.ProcessManager; +import io.spine.server.tuple.Pair; + +import java.util.Optional; + +import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; +import static io.spine.chatbot.server.google.chat.Identifiers.newSpaceId; +import static io.spine.chatbot.server.google.chat.Identifiers.newThreadId; + +final class ThreadChatProcess extends ProcessManager { + + @React(external = true) + Pair> on(BuildStateChanged e) { + var change = e.getChange(); + var buildState = change.getNewValue(); + var repositoryId = e.getId(); + var threadId = newThreadId(repositoryId.getValue()); + var spaceId = newSpaceId(buildState.getGoogleChatSpace()); + var sentMessage = GoogleChatClient.sendMessage(buildState, state().getName()); + var thread = sentMessage.getThread(); + var messageId = newMessageId(sentMessage.getName()); + var messageCreated = MessageCreated + .newBuilder() + .setId(messageId) + .setSpaceId(spaceId) + .setThreadId(threadId) + .vBuild(); + if (Strings.isNullOrEmpty(state().getName())) { + builder().setName(thread.getName()) + .setSpaceId(spaceId); + var threadCreated = ThreadCreated + .newBuilder() + .setId(threadId) + .setName(thread.getName()) + .setSpaceId(spaceId) + .vBuild(); + return Pair.withNullable(messageCreated, threadCreated); + } + return Pair.withNullable(messageCreated, null); + } +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index 19197142..1879f88d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -42,3 +42,15 @@ message MessageCreated { // ID of the thread within which the message is created if created in a threaded space. ThreadId thread_id = 3; } + +// Denotes that a recently created message created a new thread. +message ThreadCreated { + + ThreadId id = 1; + + // Resource name of the thread, in the form `spaces//threads/`. + string name = 2; + + // ID of the space within with the thread is available. + SpaceId space_id = 3; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto deleted file mode 100644 index 4357bce9..00000000 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_commands.proto +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -syntax = "proto3"; - -package spine.chatbot.google.chat; - -import "spine/options.proto"; - -option (type_url_prefix) = "type.spine.io.chatbot"; -option java_package = "io.spine.chatbot.google.chat.thread.command"; -option java_outer_classname = "ThreadCommandsProto"; -option java_multiple_files = true; - -import "spine/chatbot/google/chat/identifiers.proto"; - -// Denotes that a message was created in the space. -message InitializeThread { - - ThreadId id = 1; - - // Resource name of the thread, in the form `spaces//threads/`. - string name = 2; - - // ID of the space within with the thread is available. - SpaceId space_id = 3; -} From bf901e8e261ef2de3b2857a86fbb7ef77cd3d8aa Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 11:49:49 +0300 Subject: [PATCH 055/492] Create ThreadResource type instead of using thread name directly --- .../server/google/chat/ThreadAggregate.java | 4 +- .../server/google/chat/ThreadChatProcess.java | 11 +++-- .../server/google/chat/ThreadResources.java | 43 +++++++++++++++++++ .../chatbot/google/chat/chat_events.proto | 5 ++- .../spine/chatbot/google/chat/thread.proto | 9 +++- .../chatbot/google/chat/thread_chat.proto | 5 ++- .../chatbot/google/chat/thread_events.proto | 5 ++- 7 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index 581dce2c..d6a01516 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -37,14 +37,14 @@ ThreadInitialized on(ThreadCreated e) { return ThreadInitialized .newBuilder() .setId(e.getId()) - .setName(e.getName()) + .setThread(e.getThread()) .setSpaceId(e.getSpaceId()) .vBuild(); } @Apply private void on(ThreadInitialized e) { - builder().setName(e.getName()) + builder().setThread(e.getThread()) .setSpaceId(e.getSpaceId()); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index a9352379..27cbb243 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -36,6 +36,7 @@ import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; import static io.spine.chatbot.server.google.chat.Identifiers.newSpaceId; import static io.spine.chatbot.server.google.chat.Identifiers.newThreadId; +import static io.spine.chatbot.server.google.chat.ThreadResources.newThreadResource; final class ThreadChatProcess extends ProcessManager { @@ -46,7 +47,8 @@ Pair> on(BuildStateChanged e) { var repositoryId = e.getId(); var threadId = newThreadId(repositoryId.getValue()); var spaceId = newSpaceId(buildState.getGoogleChatSpace()); - var sentMessage = GoogleChatClient.sendMessage(buildState, state().getName()); + var currentThread = state().getThread(); + var sentMessage = GoogleChatClient.sendMessage(buildState, currentThread.getName()); var thread = sentMessage.getThread(); var messageId = newMessageId(sentMessage.getName()); var messageCreated = MessageCreated @@ -55,13 +57,14 @@ Pair> on(BuildStateChanged e) { .setSpaceId(spaceId) .setThreadId(threadId) .vBuild(); - if (Strings.isNullOrEmpty(state().getName())) { - builder().setName(thread.getName()) + if (Strings.isNullOrEmpty(currentThread.getName())) { + var newThread = newThreadResource(thread.getName()); + builder().setThread(newThread) .setSpaceId(spaceId); var threadCreated = ThreadCreated .newBuilder() .setId(threadId) - .setName(thread.getName()) + .setThread(newThread) .setSpaceId(spaceId) .vBuild(); return Pair.withNullable(messageCreated, threadCreated); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java new file mode 100644 index 00000000..3e1ee038 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.thread.ThreadResource; + +/** + * An utility for working with {@link ThreadResource}s. + */ +public final class ThreadResources { + + /** + * Prevents instantiation of this utility class. + */ + private ThreadResources() { + } + + /** Creates a new {@link ThreadResource} with the specified {@code name}. **/ + public static ThreadResource newThreadResource(String name) { + return ThreadResource + .newBuilder() + .setName(name) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index 1879f88d..a51aaa76 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -30,6 +30,7 @@ option java_outer_classname = "ChatEventsProto"; option java_multiple_files = true; import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/thread.proto"; // Denotes that a message was created in the space. message MessageCreated { @@ -48,8 +49,8 @@ message ThreadCreated { ThreadId id = 1; - // Resource name of the thread, in the form `spaces//threads/`. - string name = 2; + // Google Chat thread. + ThreadResource thread = 2; // ID of the space within with the thread is available. SpaceId space_id = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index 57e7d0d0..f57a9ff6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -39,7 +39,7 @@ message Thread { ThreadId id = 1; // Resource name of the thread, in the form `spaces//threads/`. - string name = 2; + ThreadResource thread = 2; // ID of the space within with the thread is available. SpaceId space_id = 3; @@ -47,3 +47,10 @@ message Thread { // IDs of the messages posted by the bot to the thread. repeated MessageId messages = 4; } + +// Google Chat Thread resource. +message ThreadResource { + + // Resource name of the thread, in the form `spaces//threads/`. + string name = 1 [(required) = true]; +} \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto index 3d1eadc7..6de7fb6f 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -30,6 +30,7 @@ option java_outer_classname = "ThreadChatProto"; option java_multiple_files = true; import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/thread.proto"; // A thread in Google Chat room. message ThreadChat { @@ -38,8 +39,8 @@ message ThreadChat { ThreadId id = 1; - // Resource name of the thread, in the form `spaces//threads/**`. - string name = 2; + // Google Chat thread. + ThreadResource thread = 2; // ID of the space within with the thread is available. SpaceId space_id = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index 4c0fb920..d91b7a09 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -30,14 +30,15 @@ option java_outer_classname = "ThreadEventsProto"; option java_multiple_files = true; import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/thread.proto"; // Denotes that a message was created in the space. message ThreadInitialized { ThreadId id = 1; - // Resource name of the thread, in the form `spaces//threads/`. - string name = 2; + // Google Chat thread. + ThreadResource thread = 2; // ID of the space within with the thread is available. SpaceId space_id = 3; From 4566bff24f63dacdfd1ace9e87ffdc84aaa8b37b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 11:54:36 +0300 Subject: [PATCH 056/492] Add ThreadChat repository --- .../server/google/chat/GoogleChatContext.java | 4 +- .../chat/ThreadChatProcessRepository.java | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 3ceaf0db..1e78eb06 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -80,6 +80,8 @@ public static void initialize() { public static BoundedContextBuilder newBuilder() { return BoundedContext .singleTenant(NAME) - .add(SpaceAggregate.class); + .add(SpaceAggregate.class) + .add(ThreadAggregate.class) + .add(new ThreadChatProcessRepository()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java new file mode 100644 index 00000000..33503752 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -0,0 +1,46 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.github.repository.build.event.BuildStateChanged; +import io.spine.chatbot.google.chat.ThreadId; +import io.spine.chatbot.google.chat.thread.ThreadChat; +import io.spine.server.procman.ProcessManagerRepository; +import io.spine.server.route.EventRouting; + +import static io.spine.chatbot.server.google.chat.Identifiers.newThreadId; +import static io.spine.server.route.EventRoute.withId; + +final class ThreadChatProcessRepository + extends ProcessManagerRepository { + + @OverridingMethodsMustInvokeSuper + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(BuildStateChanged.class, (event, context) -> { + var repositoryId = event.getId(); + var id = newThreadId(repositoryId.getValue()); + return withId(id); + }); + } +} From 3d2b8639949a4d35db1a1a7f8ec94e6c2ef0edae Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 12:20:42 +0300 Subject: [PATCH 057/492] Cleanup tests. Ensure events are produced --- .../github/OrganizationAggregateTest.java | 80 ++++++++++++++----- .../github/RepositoryAggregateTest.java | 71 +++++++++++----- 2 files changed, 109 insertions(+), 42 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 9a471779..8f9a3897 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -23,9 +23,13 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.net.Url; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static io.spine.net.Urls.urlOfSpec; @@ -38,32 +42,64 @@ protected BoundedContextBuilder contextBuilder() { return GitHubContext.newBuilder(); } - @Test + @Nested @DisplayName("register an organization") - void register() { - var id = OrganizationId + final class Register { + + private final OrganizationId organizationId = OrganizationId .newBuilder() .setValue("TestOrganization") .vBuild(); - var registerOrganization = RegisterOrganization - .newBuilder() - .setId(id) - .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/TestOrganization")) - .setWebsiteUrl(urlOfSpec("https://test-organization.com")) - .setName("Test Organization") - .vBuild(); - context().receivesCommand(registerOrganization); - var expectedState = Organization - .newBuilder() - .setId(id) - .setGithubUrl(urlOfSpec("https://github.com/TestOrganization")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/TestOrganization")) - .setWebsiteUrl(urlOfSpec("https://test-organization.com")) - .setName("Test Organization") - .vBuild(); - context().assertState(id, Organization.class) - .isEqualTo(expectedState); + private final Url githubUrl = urlOfSpec("https://github.com/TestOrganization"); + private final Url travisCiUrl = urlOfSpec("https://travis-ci.com/TestOrganization"); + private final Url websiteUrl = urlOfSpec("https://test-organization.com"); + private final String orgName = "Test Organization"; + private final String googleChatSpace = "spaces/qwdp123ttQ"; + + @BeforeEach + void setUp() { + var registerOrganization = RegisterOrganization + .newBuilder() + .setId(organizationId) + .setGithubUrl(githubUrl) + .setTravisCiUrl(travisCiUrl) + .setWebsiteUrl(websiteUrl) + .setName(orgName) + .setGoogleChatSpace(googleChatSpace) + .vBuild(); + context().receivesCommand(registerOrganization); + } + + @Test + @DisplayName("producing OrganizationRegistered event") + void producingEvent() { + var organizationRegistered = OrganizationRegistered + .newBuilder() + .setId(organizationId) + .setGithubUrl(githubUrl) + .setTravisCiUrl(travisCiUrl) + .setWebsiteUrl(websiteUrl) + .setName(orgName) + .setGoogleChatSpace(googleChatSpace) + .vBuild(); + context().assertEvent(organizationRegistered); + } + + @Test + @DisplayName("setting organization state") + void settingState() { + var expectedState = Organization + .newBuilder() + .setId(organizationId) + .setGithubUrl(githubUrl) + .setTravisCiUrl(travisCiUrl) + .setWebsiteUrl(websiteUrl) + .setName(orgName) + .setGoogleChatSpace(googleChatSpace) + .vBuild(); + context().assertState(organizationId, Organization.class) + .isEqualTo(expectedState); + } } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index db823ae2..da7609fa 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -23,9 +23,13 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.github.repository.event.RepositoryRegistered; +import io.spine.net.Url; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static io.spine.net.Urls.urlOfSpec; @@ -38,30 +42,57 @@ protected BoundedContextBuilder contextBuilder() { return GitHubContext.newBuilder(); } - @Test + @Nested @DisplayName("register a repository") - void register() { - var id = RepositoryId + final class Register { + + private final RepositoryId repositoryId = RepositoryId .newBuilder() .setValue("SpineEventEngine/base") .vBuild(); - var registerRepository = RegisterRepository - .newBuilder() - .setId(id) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) - .setName("Spine base") - .vBuild(); - context().receivesCommand(registerRepository); - var expectedState = Repository - .newBuilder() - .setId(id) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) - .setName("Spine base") - .vBuild(); - context().assertState(id, Repository.class) - .isEqualTo(expectedState); + private final Url githubUrl = urlOfSpec("https://github.com/SpineEventEngine/base"); + private final Url travisCiUrl = + urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base"); + private final String repositoryName = "Spine Base"; + + @BeforeEach + void setUp() { + var registerRepository = RegisterRepository + .newBuilder() + .setId(repositoryId) + .setGithubUrl(githubUrl) + .setTravisCiUrl(travisCiUrl) + .setName(repositoryName) + .vBuild(); + context().receivesCommand(registerRepository); + } + + @Test + @DisplayName("producing RepositoryRegistered event") + void producingEvent() { + var repositoryRegistered = RepositoryRegistered + .newBuilder() + .setId(repositoryId) + .setGithubUrl(githubUrl) + .setTravisCiUrl(travisCiUrl) + .setName(repositoryName) + .vBuild(); + context().assertEvent(repositoryRegistered); + } + + @Test + @DisplayName("setting repository state") + void settingState() { + var expectedState = Repository + .newBuilder() + .setId(repositoryId) + .setGithubUrl(githubUrl) + .setTravisCiUrl(travisCiUrl) + .setName(repositoryName) + .vBuild(); + context().assertState(repositoryId, Repository.class) + .isEqualTo(expectedState); + } } } From e63e93f19e749123889f19ff6a41c80d4c575046 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 12:20:55 +0300 Subject: [PATCH 058/492] Add utility tests --- .../server/google/chat/IdentifiersTest.java | 32 +++++++++++++++++++ .../google/chat/ThreadResourcesTest.java | 32 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java new file mode 100644 index 00000000..2b792e4f --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("Identifiers should") +final class IdentifiersTest extends UtilityClassTest { + + IdentifiersTest() { + super(Identifiers.class); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java new file mode 100644 index 00000000..8c7145fb --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("ThreadResources should") +final class ThreadResourcesTest extends UtilityClassTest { + + ThreadResourcesTest() { + super(ThreadResources.class); + } +} From 3d80940ae0cfa759453f41700d0ca54933fd1e55 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 12:26:17 +0300 Subject: [PATCH 059/492] Cleanup Space tests --- .../server/google/chat/SpaceAggregate.java | 1 - .../chatbot/google/chat/space_commands.proto | 3 - .../chatbot/google/chat/space_events.proto | 3 - .../google/chat/SpaceAggregateTest.java | 68 ++++++++++++------- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 31901319..6dcfe51a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -35,7 +35,6 @@ SpaceRegistered handle(RegisterSpace c) { var result = SpaceRegistered .newBuilder() .setId(c.getId()) - .setName(c.getName()) .setSingleUserBotDm(c.getSingleUserBotDm()) .setThreaded(c.getThreaded()) .setDisplayName(c.getDisplayName()) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 76500cab..48a5400c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -35,9 +35,6 @@ message RegisterSpace { SpaceId id = 1 [(required) = true]; - // Resource name of the space, in the form "spaces/*". - string name = 2 [(required) = true]; - // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto index 3c7f5aa1..4fbfc09a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -35,9 +35,6 @@ message SpaceRegistered { SpaceId id = 1 [(required) = true]; - // Resource name of the space, in the form "spaces/*". - string name = 2 [(required) = true]; - // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 2de3f812..7d58cb30 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -23,9 +23,12 @@ import io.spine.chatbot.google.chat.Space; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; +import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @DisplayName("SpaceAggregate should") @@ -36,30 +39,49 @@ protected BoundedContextBuilder contextBuilder() { return GoogleChatContext.newBuilder(); } - @Test + @Nested @DisplayName("register a space") - void register() { - var id = SpaceId - .newBuilder() - .setValue("spaces/qwroi12h3") - .vBuild(); - var registerOrganization = RegisterSpace - .newBuilder() - .setId(id) - .setName(id.getValue()) - .setThreaded(true) - .setDisplayName("Spine Developers") - .vBuild(); - context().receivesCommand(registerOrganization); + final class Register { - var expectedState = Space - .newBuilder() - .setId(id) - .setName(id.getValue()) - .setThreaded(true) - .setDisplayName("Spine Developers") - .vBuild(); - context().assertState(id, Space.class) - .isEqualTo(expectedState); + private final SpaceId spaceId = SpaceId.newBuilder() + .setValue("spaces/poqwdpQ21") + .vBuild(); + private final String displayName = "Spine Developers"; + + @BeforeEach + void setUp() { + var registerSpace = RegisterSpace + .newBuilder() + .setId(spaceId) + .setThreaded(true) + .setDisplayName(displayName) + .vBuild(); + context().receivesCommand(registerSpace); + } + + @Test + @DisplayName("producing SpaceRegistered event") + void producingEvent() { + var spaceRegistered = SpaceRegistered + .newBuilder() + .setId(spaceId) + .setDisplayName(displayName) + .setThreaded(true) + .vBuild(); + context().assertEvent(spaceRegistered); + } + + @Test + @DisplayName("setting Space state") + void settingState() { + var expectedState = Space + .newBuilder() + .setId(spaceId) + .setThreaded(true) + .setDisplayName(displayName) + .vBuild(); + context().assertState(spaceId, Space.class) + .isEqualTo(expectedState); + } } } From f5fce7030f83c508a1d9c448875a2bdc59a4cc8e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 12:35:29 +0300 Subject: [PATCH 060/492] Add ThreadAggregate tests --- .../server/google/chat/GoogleChatContext.java | 2 +- .../chat/ThreadAggregateRepository.java | 39 +++++ .../google/chat/ThreadAggregateTest.java | 157 ++++++++++++++++++ 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 1e78eb06..8f16ed37 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -81,7 +81,7 @@ public static BoundedContextBuilder newBuilder() { return BoundedContext .singleTenant(NAME) .add(SpaceAggregate.class) - .add(ThreadAggregate.class) + .add(new ThreadAggregateRepository()) .add(new ThreadChatProcessRepository()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java new file mode 100644 index 00000000..92c8d648 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.ThreadId; +import io.spine.chatbot.google.chat.event.MessageCreated; +import io.spine.chatbot.google.chat.event.ThreadCreated; +import io.spine.server.aggregate.AggregateRepository; +import io.spine.server.route.EventRouting; + +import static io.spine.server.route.EventRoute.withId; + +class ThreadAggregateRepository extends AggregateRepository { + + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(ThreadCreated.class, (event, context) -> withId(event.getId())); + routing.route(MessageCreated.class, (event, context) -> withId(event.getThreadId())); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java new file mode 100644 index 00000000..b3fa4e00 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -0,0 +1,157 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.MessageId; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.ThreadId; +import io.spine.chatbot.google.chat.event.MessageCreated; +import io.spine.chatbot.google.chat.event.ThreadCreated; +import io.spine.chatbot.google.chat.thread.Thread; +import io.spine.chatbot.google.chat.thread.ThreadResource; +import io.spine.chatbot.google.chat.thread.event.MessageAdded; +import io.spine.chatbot.google.chat.thread.event.ThreadInitialized; +import io.spine.server.BoundedContextBuilder; +import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; +import static io.spine.chatbot.server.google.chat.ThreadResources.newThreadResource; + +@DisplayName("ThreadAggregate should") +final class ThreadAggregateTest extends ContextAwareTest { + + @Override + protected BoundedContextBuilder contextBuilder() { + return GoogleChatContext.newBuilder(); + } + + @Nested + @DisplayName("initialize a thread") + final class InitThread { + + private final ThreadId threadId = ThreadId.newBuilder() + .setValue("SpineEventEngine/base") + .vBuild(); + private final SpaceId spaceId = SpaceId.newBuilder() + .setValue("spaces/qpojdwpiq1241") + .vBuild(); + private final ThreadResource threadResource = + newThreadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); + + @BeforeEach + void setUp() { + var threadCreated = ThreadCreated + .newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResource) + .vBuild(); + context().receivesEvent(threadCreated); + } + + @Test + @DisplayName("producing ThreadInitialized event") + void producingEvent() { + var threadInitialized = ThreadInitialized + .newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResource) + .vBuild(); + context().assertEvent(threadInitialized); + } + + @Test + @DisplayName("setting aggregate state") + void settingState() { + var state = Thread.newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResource) + .vBuild(); + context().assertState(threadId, Thread.class) + .isEqualTo(state); + } + } + + @Nested + @DisplayName("add created message") + final class AddMessage { + + private final ThreadId threadId = ThreadId.newBuilder() + .setValue("SpineEventEngine/base") + .vBuild(); + private final SpaceId spaceId = SpaceId.newBuilder() + .setValue("spaces/qpojdwpiq1241") + .vBuild(); + private final MessageId messageId = + newMessageId("spaces/qpojdwpiq1241/messages/dqpwjpop12"); + private final ThreadResource threadResource = + newThreadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); + + @BeforeEach + void setUp() { + var threadCreated = ThreadCreated + .newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResource) + .vBuild(); + var messageCreated = MessageCreated + .newBuilder() + .setId(messageId) + .setSpaceId(spaceId) + .setThreadId(threadId) + .vBuild(); + context().receivesEvent(threadCreated) + .receivesEvent(messageCreated); + } + + @Test + @DisplayName("producing MessageAdded event") + void producingEvent() { + var messageAdded = MessageAdded + .newBuilder() + .setId(messageId) + .setThreadId(threadId) + .vBuild(); + context().assertEvent(messageAdded); + } + + @Test + @DisplayName("setting aggregate state") + void settingState() { + var state = Thread + .newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResource) + .addMessages(messageId) + .vBuild(); + context().assertState(threadId, Thread.class) + .isEqualTo(state); + } + } +} From 9a41de63383cbe68b7329a3cebb7c06026f7d14e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 14:19:39 +0300 Subject: [PATCH 061/492] Fix controller and test --- .../chatbot/OrganizationsController.java | 16 ++++------ .../chatbot/OrganizationsControllerTest.java | 29 +++++++------------ 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java index 3c1085c3..fe90cbb5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java @@ -20,29 +20,25 @@ package io.spine.chatbot; +import com.google.common.collect.ImmutableList; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.spine.chatbot.github.organization.Organization; import io.spine.client.Client; -import java.util.stream.Collectors; - import static io.spine.chatbot.Application.SERVER_NAME; @Controller("/organizations") public class OrganizationsController { @Get - public String index() { + public ImmutableList index() { Client client = Client .inProcess(SERVER_NAME) .build(); - String result = client.asGuest() - .select(Organization.class) - .run() - .stream() - .map(String::valueOf) - .collect(Collectors.joining()); + ImmutableList result = client.asGuest() + .select(Organization.class) + .run(); return result; } -} \ No newline at end of file +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java index 663119f3..280cb550 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java @@ -20,47 +20,38 @@ package io.spine.chatbot; -import io.micronaut.context.ApplicationContext; import io.micronaut.http.HttpRequest; import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.annotation.Client; import io.micronaut.runtime.server.EmbeddedServer; import io.micronaut.test.annotation.MicronautTest; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import javax.inject.Inject; + import static io.spine.chatbot.Application.initializeSpine; import static org.junit.jupiter.api.Assertions.assertEquals; @MicronautTest final class OrganizationsControllerTest { - private static EmbeddedServer server; - private static HttpClient client; + @Inject + EmbeddedServer server; + + @Inject + @Client("/") + HttpClient client; @BeforeAll static void setupServer() { initializeSpine(); - server = ApplicationContext.run(EmbeddedServer.class); - client = server - .getApplicationContext() - .createBean(HttpClient.class, server.getURL()); - } - - @AfterAll - static void stopServer() { - if (server != null) { - server.stop(); - } - if (client != null) { - client.stop(); - } } @Test void testFunction() { String actual = client.toBlocking() .retrieve(HttpRequest.GET("/organizations")); - assertEquals("Example Response", actual); + assertEquals("[]", actual); } } From 8ea91c94b0f626b51d6324427776fcfd3577908e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 14:22:59 +0300 Subject: [PATCH 062/492] Bump errorprone version --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index cac1b9bf..7e65003d 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ plugins { id 'com.google.cloud.tools.jib' version '2.3.0' apply false id "net.saliman.properties" version "1.5.1" apply false id 'io.spine.tools.gradle.bootstrap' version '1.5.8' apply false - id "net.ltgt.errorprone" version "1.2.0" apply false + id "net.ltgt.errorprone" version "1.2.1" apply false } allprojects { @@ -52,7 +52,7 @@ subprojects { } dependencies { - errorprone "com.google.errorprone:error_prone_core:2.3.4" + errorprone "com.google.errorprone:error_prone_core:2.4.0" annotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) annotationProcessor("io.micronaut:micronaut-inject-java") annotationProcessor("io.micronaut:micronaut-validation") @@ -114,4 +114,4 @@ subprojects { minimize() mergeServiceFiles() } -} \ No newline at end of file +} From ca475013ba25610a83958983c02af85b5a56ff0a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 14:40:34 +0300 Subject: [PATCH 063/492] Add missing package.info --- .../io/spine/chatbot/api/package-info.java | 30 +++++++++++++++++++ .../java/io/spine/chatbot/package-info.java | 30 +++++++++++++++++++ .../main/java/io/spine/net/package-info.java | 30 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/package-info.java create mode 100644 google-chat-bot/src/main/java/io/spine/net/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java new file mode 100644 index 00000000..b15f8cd4 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains server-side reusable APIs. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.api; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java new file mode 100644 index 00000000..cd6e4d2a --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package Spine's Google Chat Bot application and environment configurations. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/net/package-info.java b/google-chat-bot/src/main/java/io/spine/net/package-info.java new file mode 100644 index 00000000..fde4c7f5 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/net/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package Spine .net utilities. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.net; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; From 8553df554d68115a685172acde3ef1ad02057c88 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 14:45:50 +0300 Subject: [PATCH 064/492] Cleanup clients, add docs. --- .../spine/chatbot/api/GoogleChatClient.java | 80 ++++++++----------- .../io/spine/chatbot/api/TravisClient.java | 21 ++--- 2 files changed, 46 insertions(+), 55 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 23467375..1c514759 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -40,9 +40,9 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.base.Environment; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.net.Url; -import io.spine.net.Urls; import io.spine.validate.Validate; import javax.annotation.Nullable; @@ -54,20 +54,41 @@ import static com.google.common.base.Strings.isNullOrEmpty; +/** + * Google Chat client. + */ public final class GoogleChatClient { private static final String BOT_NAME = "Spine Chat Bot"; private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; + /** Prevents direct instantiation. **/ private GoogleChatClient() { } + /** + * Sends {@link BuildState} status message to a related space and thread. + * + *

If the thread name is not specified the message is sent to a new thread. + * + * @return a sent message + */ + public static Message sendMessage(BuildState buildState, @Nullable String threadName) { + var message = buildStateMessage(buildState, threadName); + return sendMessage(hangoutsChat(), buildState.getGoogleChatSpace(), message); + } + private static HangoutsChat hangoutsChat() { try { - var keyStream = Files.newInputStream(Paths.get("spine-chat-bot-ea2e6c200084.json")); - - var credentials = GoogleCredentials.fromStream(keyStream) + GoogleCredentials credentials; + if (Environment.instance() + .isProduction()) { + credentials = GoogleCredentials.getApplicationDefault(); + } else { + var keyStream = Files.newInputStream(Paths.get("spine-chat-bot-ea2e6c200084.json")); + credentials = GoogleCredentials.fromStream(keyStream) .createScoped(CHAT_BOT_SCOPE); + } var credentialsAdapter = new HttpCredentialsAdapter(credentials); var chat = new HangoutsChat.Builder( GoogleNetHttpTransport.newTrustedTransport(), @@ -83,27 +104,24 @@ private static HangoutsChat hangoutsChat() { private static List listSpaces(HangoutsChat chat) { try { - return chat.spaces() - .list() - .execute() - .getSpaces(); + return chat + .spaces() + .list() + .execute() + .getSpaces(); } catch (IOException e) { throw new RuntimeException("Unable to retrieve available spaces.", e); } } - public static Message sendMessage(BuildState buildState, @Nullable String threadName) { - var message = buildStateMessage(buildState, threadName); - return sendMessage(hangoutsChat(), buildState.getGoogleChatSpace(), message); - } - @CanIgnoreReturnValue private static Message sendMessage(HangoutsChat chat, String space, Message message) { try { - return chat.spaces() - .messages() - .create(space, message) - .execute(); + return chat + .spaces() + .messages() + .create(space, message) + .execute(); } catch (IOException e) { throw new RuntimeException("Unable to send message to space " + space, e); } @@ -182,32 +200,4 @@ private static Message buildStateMessage(BuildState buildState, @Nullable String } return message; } - - public static void main(String[] args) { - var chat = hangoutsChat(); - listSpaces(chat).forEach(System.out::println); - var commit = BuildState.Commit - .newBuilder() - .setCommittedAt("2020-06-03T14:45:02Z") - .setMessage( - "My test commit with a very long description and even\n\n Sub-description, cause it is very relevant and has additional reference to issue\n #749 and a lot of kind words!") - .setSha("d97c603d5e855d0d211382f78916ad085ba04743") - .setCompareUrl(Urls.urlOfSpec( - "https://github.com/SpineEventEngine/base/commit/d97c603d5e855d0d211382f78916ad085ba04743")) - .setAuthoredBy("yuri-sergiichuk") - .vBuild(); - BuildState buildState = BuildState - .newBuilder() - .setRepositorySlug("SpineEventEngine/base") - .setNumber("5292") - .setState("failed") - .setLastCommit(commit) - .setTravisCiUrl(Urls.urlOfSpec( - "https://travis-ci.com/github/SpineEventEngine/base/builds/166723382")) - .setBranch("master") - .setCreatedBy("yuri-sergiichuk") - .setGoogleChatSpace("spaces/AAAAnLxnh_o") - .vBuild(); - System.out.println(sendMessage(buildState, "spaces/AAAAnLxnh_o/threads/TPFMA4dK0_4")); - } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index b7bd2c75..daeff326 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -31,7 +31,10 @@ import static io.spine.chatbot.api.JsonProtoBodyHandler.jsonBodyHandler; -final class TravisClient { +/** + * A Travis CI API client. + */ +public final class TravisClient { private static final HttpClient CLIENT = HttpClient.newHttpClient(); private static final String BASE_URL = "https://api.travis-ci.com"; @@ -41,14 +44,18 @@ final class TravisClient { private final String apiToken; - private TravisClient(String token) { + public TravisClient(String token) { apiToken = token; } + /** + * Queries Travis CI build statuses for a repository determined by the supplied repository slug. + */ public BuildsResponse queryBuildsFor(String repoSlug) { var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); - var repoBuilds = - "/repo/" + encodedSlug + "/builds?limit=1&branch.name=master?include=build.commit"; + var repoBuilds = "/repo/" + + encodedSlug + + "/builds?limit=1&branch.name=master?include=build.commit"; var request = apiRequest(repoBuilds, apiToken); try { var result = CLIENT.send(request, jsonBodyHandler(BuildsResponse.class)); @@ -71,10 +78,4 @@ private static HttpRequest.Builder authorizedApiRequest(String token) { .header(API_HEADER, API_VERSION) .header(AUTH_HEADER, "token " + token); } - - public static void main(String[] args) { - var client = new TravisClient(""); - var response = client.queryBuildsFor("SpineEventEngine/base"); - System.out.println(response); - } } From 740d0e93d36d71aa1d1608ab86ddd0b9a555bfc9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 17:15:46 +0300 Subject: [PATCH 065/492] Do post commands to request repository checks. --- .../java/io/spine/chatbot/CronController.java | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java index 631ee629..0e816094 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java @@ -20,20 +20,29 @@ package io.spine.chatbot; +import com.google.common.collect.ImmutableSet; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; +import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.client.Client; +import io.spine.client.CommandRequest; import java.util.Collection; import java.util.stream.Collectors; import static io.spine.chatbot.Application.SERVER_NAME; +import static io.spine.util.Exceptions.newIllegalStateException; +/** + * A REST controller for handling CRON-based requests from GCP. + */ @Controller("/cron") public class CronController { + /** Requests build status checks for registered repositories. **/ @Post("/repositories/check") public String checkRepositoryStatuses() { Client client = Client @@ -49,11 +58,28 @@ public String checkRepositoryStatuses() { .select(OrganizationRepositories.class) .byId(orgIds) .run(); - var repositoryIds = orgRepos.stream() - .map(OrganizationRepositories::getRepositoriesList) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - + orgRepos.stream() + .map(OrganizationRepositories::getRepositoriesList) + .flatMap(Collection::stream) + .map(CronController::newCheckRepoBuildCommand) + .map(client.asGuest()::command) + .map(request -> request.onStreamingError(CronController::throwProcessingError)) + .map(CommandRequest::post) + .flatMap(ImmutableSet::stream) + .forEach(client.subscriptions()::cancel); return "success"; } + + private static void throwProcessingError(Throwable throwable) { + throw newIllegalStateException( + throwable, "An error while processing the command result." + ); + } + + private static CheckRepositoryBuild newCheckRepoBuildCommand(RepositoryId id) { + return CheckRepositoryBuild + .newBuilder() + .setId(id) + .vBuild(); + } } From ff36a94614b569cd01607afd8702c465d8bc0cf6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 17:15:52 +0300 Subject: [PATCH 066/492] Add docs --- .../src/main/java/io/spine/chatbot/Application.java | 3 +++ .../main/java/io/spine/chatbot/ChatBotServerEnvironment.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index b15d18ed..1fc7f89a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -28,10 +28,12 @@ import java.io.IOException; +/** The entry point to the Google Chat Bot application. **/ public final class Application { static final String SERVER_NAME = "ChatBotServer"; + /** Prevents direct instantiation. **/ private Application() { } @@ -40,6 +42,7 @@ public static void main(String[] args) { Micronaut.run(Application.class, args); } + /** Initializes Spine server environment and starts Spine {@link Server}. **/ @VisibleForTesting static void initializeSpine() { ChatBotServerEnvironment.initializeEnvironment(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index d40dcd7a..decdb5a5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -25,6 +25,7 @@ import io.spine.server.storage.memory.InMemoryStorageFactory; import io.spine.server.transport.memory.InMemoryTransportFactory; +/** ChatBot server environment definition. **/ final class ChatBotServerEnvironment { /** @@ -33,6 +34,7 @@ final class ChatBotServerEnvironment { private ChatBotServerEnvironment() { } + /** Initializes {@link ServerEnvironment} for ChatBot. **/ static void initializeEnvironment() { ServerEnvironment se = ServerEnvironment.instance(); se.configureStorage(InMemoryStorageFactory.newInstance()); From 94b31b38cb77864bc133ff338b247e92474ff0d7 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 17:22:33 +0300 Subject: [PATCH 067/492] Add stub DS indexes --- google-chat-bot/src/main/resources/index.yaml | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 google-chat-bot/src/main/resources/index.yaml diff --git a/google-chat-bot/src/main/resources/index.yaml b/google-chat-bot/src/main/resources/index.yaml new file mode 100644 index 00000000..a1a0a66e --- /dev/null +++ b/google-chat-bot/src/main/resources/index.yaml @@ -0,0 +1,97 @@ +# This file is the configuration of the Cloud Datastore DB indexes. +# To update the index, modify the file and run: +# +# $ gcloud datastore indexes create google-chat-bot/src/main/resources/index.yaml --project +# + +indexes: + + # Common index for all the applications. + - + - kind: spine.core.Event + ancestor: no + properties: + - name: type + - name: created + + # Index required for `DsInboxStorage.readAll` query. + + - kind: spine.server.delivery.InboxMessage + ancestor: yes + properties: + - name: inbox_shard + - name: of_total_inbox_shards + - name: received_at + - name: version + + # Index required for `DsInboxStorage.newestMessageToDeliver` query. + + - kind: spine.server.delivery.InboxMessage + ancestor: yes + properties: + - name: inbox_shard + - name: of_total_inbox_shards + - name: status + + - kind: spine.system.server.CommandLifecycle + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot + + - kind: spine.system.server.EntityHistory + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot + + - kind: purephotos.photos.order.Order + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot + + - kind: spine.chatbot.github.Organization + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot + + - kind: spine.chatbot.github.Repository + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot + + - kind: spine.chatbot.google.chat.Space + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot + + - kind: spine.chatbot.google.chat.Thread + properties: + - name: aggregate_id + - name: version + direction: desc + - name: created + direction: desc + - name: snapshot From 1ed45db94b0fc13660a1100aaac831a41e932056 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 17:33:01 +0300 Subject: [PATCH 068/492] Add spine-datastore dependency --- google-chat-bot/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 58de0550..56ed23af 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -28,6 +28,9 @@ spine { } dependencies { + + implementation "io.spine.gcloud:spine-datastore:1.5.0" + implementation 'com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9' implementation 'com.google.auth:google-auth-library-oauth2-http:0.20.0' testImplementation "io.spine:spine-testutil-server:${spine.version()}" From eae8aa29b9529d65db6b9f5fec97227609dc3157 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 17:42:30 +0300 Subject: [PATCH 069/492] Fix indexes padding --- google-chat-bot/src/main/resources/index.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/resources/index.yaml b/google-chat-bot/src/main/resources/index.yaml index a1a0a66e..e6410f8e 100644 --- a/google-chat-bot/src/main/resources/index.yaml +++ b/google-chat-bot/src/main/resources/index.yaml @@ -7,12 +7,11 @@ indexes: # Common index for all the applications. - - - kind: spine.core.Event - ancestor: no - properties: - - name: type - - name: created + ancestor: no + properties: + - name: type + - name: created # Index required for `DsInboxStorage.readAll` query. From e6fe024453f578bf577124d1cdd8ce3634e09fc6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 17:51:16 +0300 Subject: [PATCH 070/492] Extract creation of the Travis build URL --- .../chatbot/server/github/RepositoryBuildProcess.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index b427d2df..892c7660 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -30,6 +30,7 @@ import io.spine.chatbot.github.repository.build.event.BuildStateChanged; import io.spine.chatbot.travis.Build; import io.spine.chatbot.travis.Commit; +import io.spine.net.Url; import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; @@ -64,7 +65,6 @@ BuildStateChanged handle(CheckRepositoryBuild c) { private static BuildState from(Build build) { var slug = build.getRepository() .getSlug(); - var spec = String.format("https://travis-ci.com/github/%s/builds/%d", slug, build.getId()); return BuildState .newBuilder() .setState(build.getState()) @@ -75,10 +75,15 @@ private static BuildState from(Build build) { .setCreatedBy(build.getCreatedBy() .getLogin()) .setRepositorySlug(slug) - .setTravisCiUrl(Urls.urlOfSpec(spec)) + .setTravisCiUrl(newTravisCiUrlFor(slug, build.getId())) .vBuild(); } + private static Url newTravisCiUrlFor(String repoSlug, long buildId) { + var spec = String.format("https://travis-ci.com/github/%s/builds/%d", repoSlug, buildId); + return Urls.urlOfSpec(spec); + } + private static BuildState.Commit from(Commit commit) { return BuildState.Commit .newBuilder() From 6acd287a0618a7f3f03cb4e57637f4efd1985cae Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 18:25:34 +0300 Subject: [PATCH 071/492] Make the class final --- .../chatbot/server/google/chat/ThreadAggregateRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java index 92c8d648..ce8186f3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java @@ -28,7 +28,7 @@ import static io.spine.server.route.EventRoute.withId; -class ThreadAggregateRepository extends AggregateRepository { +final class ThreadAggregateRepository extends AggregateRepository { @Override protected void setupEventRouting(EventRouting routing) { From 440378942ad2fced78883c8cd2ef5b5e760cb317 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 9 Jun 2020 18:34:28 +0300 Subject: [PATCH 072/492] Add API links --- .../src/main/java/io/spine/chatbot/api/GoogleChatClient.java | 2 ++ .../src/main/java/io/spine/chatbot/api/TravisClient.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 1c514759..ff34cd1b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -56,6 +56,8 @@ /** * Google Chat client. + * + * @see Hangouts Chat API */ public final class GoogleChatClient { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index daeff326..a5d4af83 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -33,6 +33,8 @@ /** * A Travis CI API client. + * + * @see Travis CI API */ public final class TravisClient { From a6c3f1e85c736a3381fa8b95c38ce496df13e7dc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 10:21:31 +0300 Subject: [PATCH 073/492] Add docs for public API --- .../spine/chatbot/api/JsonProtoBodyHandler.java | 3 ++- .../java/io/spine/chatbot/api/TravisClient.java | 3 +++ .../chatbot/server/github/GitHubContext.java | 14 +++++++------- .../server/google/chat/GoogleChatContext.java | 15 +++++++++------ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java index 1f8d0ac4..269981e6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java @@ -37,7 +37,8 @@ private JsonProtoBodyHandler(Class type) { this.type = type; } - public static JsonProtoBodyHandler jsonBodyHandler(Class type) { + /** Creates a body handler for a specified type. **/ + static JsonProtoBodyHandler jsonBodyHandler(Class type) { return new JsonProtoBodyHandler<>(type); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index a5d4af83..b0861c53 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -46,6 +46,9 @@ public final class TravisClient { private final String apiToken; + /** + * Creates a new Travis client with the specified API token. + */ public TravisClient(String token) { apiToken = token; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 82463653..8135163d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -28,7 +28,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** - * Provides BoundedContestBuilder for the GitHub Context. + * Provides {@link BoundedContextBuilder} for the GitHub context. */ public final class GitHubContext { @@ -45,16 +45,16 @@ public final class GitHubContext { */ static final String NAME = "GitHub"; - /** - * Prevents instantiation of this utility class. - */ + /** Prevents instantiation of this utility class. **/ private GitHubContext() { } + /** Returns command bus associated with the bounded context. **/ public static CommandBus commandBus() { return context().commandBus(); } + /** Returns query service associated with the bounded context. **/ public static synchronized QueryService queryService() { if (queryService == null) { queryService = QueryService @@ -65,6 +65,7 @@ public static synchronized QueryService queryService() { return queryService; } + /** Returns the bounded context. **/ public static synchronized BoundedContext context() { if (context == null) { context = newBuilder().build(); @@ -72,14 +73,13 @@ public static synchronized BoundedContext context() { return context; } + /** Initializes bounded context and associated services. **/ @SuppressWarnings("ResultOfMethodCallIgnored") public static void initialize() { queryService(); } - /** - * Creates a new instance of the GitHub Context builder. - */ + /** Creates a new instance of the GitHub Context builder. **/ public static BoundedContextBuilder newBuilder() { return BoundedContext .singleTenant(NAME) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 8f16ed37..553d1958 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -27,6 +27,9 @@ import io.spine.server.commandbus.CommandBus; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +/** + * Provides {@link BoundedContextBuilder} for the Google Chat context. + */ public final class GoogleChatContext { @MonotonicNonNull @@ -42,16 +45,16 @@ public final class GoogleChatContext { */ static final String NAME = "GoogleChat"; - /** - * Prevents instantiation of this utility class. - */ + /** Prevents instantiation of this utility class. **/ private GoogleChatContext() { } + /** Returns command bus associated with the bounded context. **/ public static CommandBus commandBus() { return context().commandBus(); } + /** Returns query service associated with the bounded context. **/ public static synchronized QueryService queryService() { if (queryService == null) { queryService = QueryService @@ -62,6 +65,7 @@ public static synchronized QueryService queryService() { return queryService; } + /** Returns the bounded context. **/ public static synchronized BoundedContext context() { if (context == null) { context = newBuilder().build(); @@ -69,14 +73,13 @@ public static synchronized BoundedContext context() { return context; } + /** Initializes bounded context and associated services. **/ @SuppressWarnings("ResultOfMethodCallIgnored") public static void initialize() { queryService(); } - /** - * Creates a new instance of the GitHub Context builder. - */ + /** Creates a new instance of the Google Chat context builder. **/ public static BoundedContextBuilder newBuilder() { return BoundedContext .singleTenant(NAME) From ebea9b0f5861acaec5e9a18e1a07647801789a17 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 10:27:11 +0300 Subject: [PATCH 074/492] Drop `id` prefix --- .../server/github/OrganizationRepositoriesRepository.java | 4 ++-- .../spine/chatbot/server/github/RepositoryAggregate.java | 4 +++- .../src/main/proto/spine/chatbot/github/repository.proto | 2 +- .../proto/spine/chatbot/github/repository_commands.proto | 2 +- .../proto/spine/chatbot/github/repository_events.proto | 2 +- .../chatbot/server/github/RepositoryAggregateTest.java | 8 ++++++++ 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java index a042025e..c21e3de1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java @@ -41,8 +41,8 @@ final class OrganizationRepositoriesRepository protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); routing.route(RepositoryRegistered.class, (event, context) -> - isNotDefault(event.getOrganizationId()) - ? withId(event.getOrganizationId()) + isNotDefault(event.getOrganization()) + ? withId(event.getOrganization()) : noTargets()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java index 58b47f88..f7c7b5e8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -39,6 +39,7 @@ RepositoryRegistered handle(RegisterRepository c) { .setName(c.getName()) .setGithubUrl(c.getGithubUrl()) .setTravisCiUrl(c.getTravisCiUrl()) + .setOrganization(c.getOrganization()) .vBuild(); return result; } @@ -47,6 +48,7 @@ RepositoryRegistered handle(RegisterRepository c) { private void on(RepositoryRegistered e) { builder().setName(e.getName()) .setGithubUrl(e.getGithubUrl()) - .setTravisCiUrl(e.getTravisCiUrl()); + .setTravisCiUrl(e.getTravisCiUrl()) + .setOrganization(e.getOrganization()); } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 74be5b85..801cbfef 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -50,5 +50,5 @@ message Repository { spine.net.Url travis_ci_url = 4; // ID of the organization repository is related to if any. - OrganizationId organization_id = 5; + OrganizationId organization = 5; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 7e8742de..c1511e6a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -48,5 +48,5 @@ message RegisterRepository { spine.net.Url travis_ci_url = 4 [(required) = true]; // ID of the organization repository is related to if any. - OrganizationId organization_id = 5; + OrganizationId organization = 5; } \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index eab4abd6..652ac117 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -48,5 +48,5 @@ message RepositoryRegistered { spine.net.Url travis_ci_url = 4 [(required) = true]; // ID of the organization repository is related to if any. - OrganizationId organization_id = 5; + OrganizationId organization = 5; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index da7609fa..846e4d47 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.github; +import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; @@ -50,6 +51,10 @@ final class Register { .newBuilder() .setValue("SpineEventEngine/base") .vBuild(); + private final OrganizationId organizationId = OrganizationId + .newBuilder() + .setValue("SpineEventEngine") + .vBuild(); private final Url githubUrl = urlOfSpec("https://github.com/SpineEventEngine/base"); private final Url travisCiUrl = @@ -64,6 +69,7 @@ void setUp() { .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setName(repositoryName) + .setOrganization(organizationId) .vBuild(); context().receivesCommand(registerRepository); } @@ -77,6 +83,7 @@ void producingEvent() { .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setName(repositoryName) + .setOrganization(organizationId) .vBuild(); context().assertEvent(repositoryRegistered); } @@ -90,6 +97,7 @@ void settingState() { .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setName(repositoryName) + .setOrganization(organizationId) .vBuild(); context().assertState(repositoryId, Repository.class) .isEqualTo(expectedState); From e889a7edd16f1bec7ff7269d3a5c0daa90149ee5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 11:50:49 +0300 Subject: [PATCH 075/492] Uppercase app name --- google-chat-bot/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/resources/application.yml b/google-chat-bot/src/main/resources/application.yml index 21a10d1c..b554a48e 100644 --- a/google-chat-bot/src/main/resources/application.yml +++ b/google-chat-bot/src/main/resources/application.yml @@ -20,4 +20,4 @@ micronaut: application: - name: chatBot + name: ChatBot From 2b79276f7753fd26715f5557434b197c6d4d327e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 12:27:16 +0300 Subject: [PATCH 076/492] Always use ADC --- .../java/io/spine/chatbot/api/GoogleChatClient.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index ff34cd1b..1b4d638a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -40,15 +40,12 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.spine.base.Environment; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.net.Url; import io.spine.validate.Validate; import javax.annotation.Nullable; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.List; @@ -82,15 +79,8 @@ public static Message sendMessage(BuildState buildState, @Nullable String thread private static HangoutsChat hangoutsChat() { try { - GoogleCredentials credentials; - if (Environment.instance() - .isProduction()) { - credentials = GoogleCredentials.getApplicationDefault(); - } else { - var keyStream = Files.newInputStream(Paths.get("spine-chat-bot-ea2e6c200084.json")); - credentials = GoogleCredentials.fromStream(keyStream) + var credentials = GoogleCredentials.getApplicationDefault() .createScoped(CHAT_BOT_SCOPE); - } var credentialsAdapter = new HttpCredentialsAdapter(credentials); var chat = new HangoutsChat.Builder( GoogleNetHttpTransport.newTrustedTransport(), From c84caec5fff3bc8e673b56786e6e3a0e58bc3a7d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 12:27:36 +0300 Subject: [PATCH 077/492] Store local credentials under .credentials folder --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index abbac680..7a0aa46d 100644 --- a/.gitignore +++ b/.gitignore @@ -243,3 +243,6 @@ gradle-app.setting gradle-local.properties **/generated/** + +# Local credentials folder +.credentials From d2fdcd103a7c92fc2e33209ea218e326e5f54742 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 12:29:17 +0300 Subject: [PATCH 078/492] Change image name to `chat-bot-server` --- google-chat-bot/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 56ed23af..63060649 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -40,7 +40,7 @@ mainClassName = "io.spine.chatbot.Application" jib { to { - image = "gcr.io/${gcpProject}/google-chat-bot-server" + image = "gcr.io/${gcpProject}/chat-bot-server" } container { mainClass = mainClassName From 87af1f1a87762fd7a8ec9bd1d440ea02f4190f20 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 14:39:59 +0300 Subject: [PATCH 079/492] Update readme --- README.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e4a7f72..192e0d19 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,65 @@ -Micronaut-based Google Chat-Bot +Spine ChatBot ------- +The ChatBot application is a Spine-based Google Chat [bot][chatbot-concepts] that +monitors the build statuses of Spine repositories and notifies the developers +via the [Google Chat][google-chat]. + +[chatbot-concepts]: https://developers.google.com/hangouts/chat/concepts/bots +[google-chat]: https://chat.google.com/ + +## Prerequisites + +* [JDK 11][jdk11] or newer. +* [Docker SE][docker] v19.03 or newer. + +[docker]: https://docs.docker.com/get-docker/ +[jdk11]: https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html + +## Build + +In order to build a distributive of the application, run: + +```bash +./gradlew clean build +``` + +The `.tar` and `.zip` dists should be available under `build/distributions`. + +Also, it is possible to build a Docker image using [`jib`][jib]: + +```bash +./gradlew clean build jib +``` + +[jib]: https://github.com/GoogleContainerTools/jib + +## Running locally + +It is possible to run the application as a docker image locally. In order to do that, please make +sure you have saved the appropriate GCP credentials at `.credentials/gcp-adc.json`. + +Then run the following script from the repository root folder: + +```bash +export APP_PORT=8080 +export LOCAL_PORT=9090 +export CONTAINER_CREDENTIALS_PATH="/tmp/keys/gcp-adc.json" +export LOCAL_CREDENTIALS_PATH="${PWD}./credentials/gcp-adc.json" +docker run \ + --tty \ + --rm \ + -p "${LOCAL_PORT}:${APP_PORT}" \ + -e "PORT=${APP_PORT}" \ + -e "MICRONAUT_SERVER_PORT=${APP_PORT}" \ + -e "GOOGLE_APPLICATION_CREDENTIALS=${CONTAINER_CREDENTIALS_PATH}" + -v "${LOCAL_CREDENTIALS_PATH}:${CONTAINER_CREDENTIALS_PATH}" + gcr.io/${gcpProject}/chat-bot-server +``` + +The application will be available at `127.0.0.1:${LOCAL_PORT}` (e.g. `127.0.0.1:9090`). +Locally-supplied GCP credentials are mount into the image directly. + +For detailed ADC credentials guide for Docker see example Cloud Run [guide][cloud-run-local-guide]. + +[cloud-run-local-guide]: https://cloud.google.com/run/docs/testing/local#running_locally_using_docker_with_access_to_services From 81cc260e4281c054176794d16846311bb3e03e1a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 14:41:03 +0300 Subject: [PATCH 080/492] Use Datastore storage factory in production --- .../chatbot/ChatBotServerEnvironment.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index decdb5a5..be2cfb48 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -20,8 +20,12 @@ package io.spine.chatbot; +import com.google.cloud.datastore.DatastoreOptions; +import io.spine.base.Environment; import io.spine.server.ServerEnvironment; import io.spine.server.delivery.Delivery; +import io.spine.server.storage.StorageFactory; +import io.spine.server.storage.datastore.DatastoreStorageFactory; import io.spine.server.storage.memory.InMemoryStorageFactory; import io.spine.server.transport.memory.InMemoryTransportFactory; @@ -37,7 +41,19 @@ private ChatBotServerEnvironment() { /** Initializes {@link ServerEnvironment} for ChatBot. **/ static void initializeEnvironment() { ServerEnvironment se = ServerEnvironment.instance(); - se.configureStorage(InMemoryStorageFactory.newInstance()); + StorageFactory storageFactory; + if (Environment.instance() + .isProduction()) { + var datastore = DatastoreOptions.getDefaultInstance() + .getService(); + storageFactory = DatastoreStorageFactory + .newBuilder() + .setDatastore(datastore) + .build(); + } else { + storageFactory = InMemoryStorageFactory.newInstance(); + } + se.configureStorage(storageFactory); se.configureTransport(InMemoryTransportFactory.newInstance()); se.configureDelivery(Delivery.localAsync()); } From 92c1fd9bb8bdd26966bfa09145789d362b4da222 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 15:24:34 +0300 Subject: [PATCH 081/492] Introduce GitHub context identifiers --- .../chatbot/server/github/Identifiers.java | 50 +++++++++++++++++++ .../server/google/chat/Identifiers.java | 4 +- .../server/github/IdentifiersTest.java | 33 ++++++++++++ .../github/OrganizationAggregateTest.java | 6 +-- .../github/RepositoryAggregateTest.java | 12 ++--- .../server/google/chat/IdentifiersTest.java | 2 +- 6 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java new file mode 100644 index 00000000..ce86a07e --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java @@ -0,0 +1,50 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.RepositoryId; + +/** + * An utility for working with {@link GitHubContext} identifiers. + */ +public final class Identifiers { + + /** Prevents instantiation of this utility class. **/ + private Identifiers() { + } + + /** Creates a new {@link OrganizationId} out of the specified {@code name}. **/ + public static OrganizationId newOrganizationId(String name) { + return OrganizationId + .newBuilder() + .setValue(name) + .vBuild(); + } + + /** Creates a new {@link OrganizationId} out of the specified {@code slug}. **/ + public static RepositoryId newRepositoryId(String slug) { + return RepositoryId + .newBuilder() + .setValue(slug) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java index 232e3d27..8ff9bac5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java @@ -31,9 +31,7 @@ */ public final class Identifiers { - /** - * Prevents instantiation of this utility class. - */ + /** Prevents instantiation of this utility class. **/ private Identifiers() { } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java new file mode 100644 index 00000000..5cd97e95 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.server.google.chat.Identifiers; +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("GitHub Identifiers should") +final class IdentifiersTest extends UtilityClassTest { + + IdentifiersTest() { + super(Identifiers.class); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 8f9a3897..3081d586 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -32,6 +32,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") @@ -46,10 +47,7 @@ protected BoundedContextBuilder contextBuilder() { @DisplayName("register an organization") final class Register { - private final OrganizationId organizationId = OrganizationId - .newBuilder() - .setValue("TestOrganization") - .vBuild(); + private final OrganizationId organizationId = newOrganizationId("TestOrganization"); private final Url githubUrl = urlOfSpec("https://github.com/TestOrganization"); private final Url travisCiUrl = urlOfSpec("https://travis-ci.com/TestOrganization"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 846e4d47..523ec8d1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -33,6 +33,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; +import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") @@ -47,14 +49,8 @@ protected BoundedContextBuilder contextBuilder() { @DisplayName("register a repository") final class Register { - private final RepositoryId repositoryId = RepositoryId - .newBuilder() - .setValue("SpineEventEngine/base") - .vBuild(); - private final OrganizationId organizationId = OrganizationId - .newBuilder() - .setValue("SpineEventEngine") - .vBuild(); + private final RepositoryId repositoryId = newRepositoryId("SpineEventEngine/base"); + private final OrganizationId organizationId = newOrganizationId("SpineEventEngine"); private final Url githubUrl = urlOfSpec("https://github.com/SpineEventEngine/base"); private final Url travisCiUrl = diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java index 2b792e4f..8e2e1322 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java @@ -23,7 +23,7 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("Identifiers should") +@DisplayName("GoogleChat Identifiers should") final class IdentifiersTest extends UtilityClassTest { IdentifiersTest() { From 517d76a99b3ddccfef98025a1c6aa88063d1854a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 15:24:51 +0300 Subject: [PATCH 082/492] Introduce ChatBot client --- .../java/io/spine/chatbot/CronController.java | 40 +++------ .../spine/chatbot/client/ChatBotClient.java | 84 +++++++++++++++++++ 2 files changed, 95 insertions(+), 29 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java index 0e816094..14e57d09 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java @@ -23,16 +23,11 @@ import com.google.common.collect.ImmutableSet; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; +import io.spine.chatbot.client.ChatBotClient; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.organization.Organization; -import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; -import io.spine.client.Client; import io.spine.client.CommandRequest; -import java.util.Collection; -import java.util.stream.Collectors; - import static io.spine.chatbot.Application.SERVER_NAME; import static io.spine.util.Exceptions.newIllegalStateException; @@ -42,31 +37,18 @@ @Controller("/cron") public class CronController { - /** Requests build status checks for registered repositories. **/ + /** Requests build status checks for registered listRepositories. **/ @Post("/repositories/check") public String checkRepositoryStatuses() { - Client client = Client - .inProcess(SERVER_NAME) - .build(); - var orgIds = client.asGuest() - .select(Organization.class) - .run() - .stream() - .map(Organization::getId) - .collect(Collectors.toList()); - var orgRepos = client.asGuest() - .select(OrganizationRepositories.class) - .byId(orgIds) - .run(); - orgRepos.stream() - .map(OrganizationRepositories::getRepositoriesList) - .flatMap(Collection::stream) - .map(CronController::newCheckRepoBuildCommand) - .map(client.asGuest()::command) - .map(request -> request.onStreamingError(CronController::throwProcessingError)) - .map(CommandRequest::post) - .flatMap(ImmutableSet::stream) - .forEach(client.subscriptions()::cancel); + var botClient = ChatBotClient.inProcessClient(SERVER_NAME); + botClient.listRepositories() + .stream() + .map(CronController::newCheckRepoBuildCommand) + .map(botClient.asGuest()::command) + .map(request -> request.onStreamingError(CronController::throwProcessingError)) + .map(CommandRequest::post) + .flatMap(ImmutableSet::stream) + .forEach(botClient::cancelSubscription); return "success"; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java new file mode 100644 index 00000000..a2e5d0a9 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -0,0 +1,84 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.client; + +import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.organization.Organization; +import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.client.Client; +import io.spine.client.ClientRequest; +import io.spine.client.Subscription; + +import java.util.Collection; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +public final class ChatBotClient { + + private final Client client; + + private ChatBotClient(Client client) { + this.client = client; + } + + /** Creates a new in-process client configured for the specified server. **/ + public static ChatBotClient inProcessClient(String serverName) { + Client client = Client + .inProcess(serverName) + .build(); + return new ChatBotClient(client); + } + + /** Returns Spine client quest request. **/ + public ClientRequest asGuest() { + return client.asGuest(); + } + + /** Cancels the passed subscription. **/ + @CanIgnoreReturnValue + public boolean cancelSubscription(Subscription subscription) { + return client.subscriptions() + .cancel(subscription); + } + + /** + * Returns IDs for all registered listRepositories. + */ + public ImmutableList listRepositories() { + var orgIds = client.asGuest() + .select(Organization.class) + .run() + .stream() + .map(Organization::getId) + .collect(toImmutableList()); + var orgRepos = client.asGuest() + .select(OrganizationRepositories.class) + .byId(orgIds) + .run(); + var result = orgRepos.stream() + .map(OrganizationRepositories::getRepositoriesList) + .flatMap(Collection::stream) + .collect(toImmutableList()); + return result; + } +} From 0aeb9c6322f221db78a1fb5e2d1f5cd465f639c5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 15:55:58 +0300 Subject: [PATCH 083/492] Add missing Inbox non-ancestor index --- google-chat-bot/src/main/resources/index.yaml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/main/resources/index.yaml b/google-chat-bot/src/main/resources/index.yaml index e6410f8e..ffa8850d 100644 --- a/google-chat-bot/src/main/resources/index.yaml +++ b/google-chat-bot/src/main/resources/index.yaml @@ -23,6 +23,13 @@ indexes: - name: received_at - name: version + - kind: spine.server.delivery.InboxMessage + properties: + - name: inbox_shard + - name: of_total_inbox_shards + - name: received_at + - name: version + # Index required for `DsInboxStorage.newestMessageToDeliver` query. - kind: spine.server.delivery.InboxMessage @@ -50,15 +57,6 @@ indexes: direction: desc - name: snapshot - - kind: purephotos.photos.order.Order - properties: - - name: aggregate_id - - name: version - direction: desc - - name: created - direction: desc - - name: snapshot - - kind: spine.chatbot.github.Organization properties: - name: aggregate_id From dbfc96d5689e24ac736679f76052418dcb5acaaf Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 15:58:08 +0300 Subject: [PATCH 084/492] Extract storage config into a helper function --- .../spine/chatbot/ChatBotServerEnvironment.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index be2cfb48..840294a6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -41,20 +41,22 @@ private ChatBotServerEnvironment() { /** Initializes {@link ServerEnvironment} for ChatBot. **/ static void initializeEnvironment() { ServerEnvironment se = ServerEnvironment.instance(); - StorageFactory storageFactory; + StorageFactory storageFactory = storageFactory(); + se.configureStorage(storageFactory); + se.configureTransport(InMemoryTransportFactory.newInstance()); + se.configureDelivery(Delivery.localAsync()); + } + + private static StorageFactory storageFactory() { if (Environment.instance() .isProduction()) { var datastore = DatastoreOptions.getDefaultInstance() .getService(); - storageFactory = DatastoreStorageFactory + return DatastoreStorageFactory .newBuilder() .setDatastore(datastore) .build(); - } else { - storageFactory = InMemoryStorageFactory.newInstance(); } - se.configureStorage(storageFactory); - se.configureTransport(InMemoryTransportFactory.newInstance()); - se.configureDelivery(Delivery.localAsync()); + return InMemoryStorageFactory.newInstance(); } } From 25da14c4dab0cbd4851fe73137e19a834befb31f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 17:56:56 +0300 Subject: [PATCH 085/492] Store secrets in Google Secret Manager --- README.md | 6 +- google-chat-bot/build.gradle | 1 + .../java/io/spine/chatbot/api/Secrets.java | 57 +++++++++++++++++++ .../io/spine/chatbot/api/TravisClient.java | 11 +++- .../server/github/RepositoryBuildProcess.java | 5 +- 5 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java diff --git a/README.md b/README.md index 192e0d19..bd5995c3 100644 --- a/README.md +++ b/README.md @@ -46,14 +46,16 @@ export APP_PORT=8080 export LOCAL_PORT=9090 export CONTAINER_CREDENTIALS_PATH="/tmp/keys/gcp-adc.json" export LOCAL_CREDENTIALS_PATH="${PWD}./credentials/gcp-adc.json" +export GCP_PROJECT_ID="" docker run \ --tty \ --rm \ -p "${LOCAL_PORT}:${APP_PORT}" \ -e "PORT=${APP_PORT}" \ -e "MICRONAUT_SERVER_PORT=${APP_PORT}" \ - -e "GOOGLE_APPLICATION_CREDENTIALS=${CONTAINER_CREDENTIALS_PATH}" - -v "${LOCAL_CREDENTIALS_PATH}:${CONTAINER_CREDENTIALS_PATH}" + -e "GOOGLE_APPLICATION_CREDENTIALS=${CONTAINER_CREDENTIALS_PATH}" \ + -e "GCP_PROJECT_ID=${GCP_PROJECT_ID}" \ + -v "${LOCAL_CREDENTIALS_PATH}:${CONTAINER_CREDENTIALS_PATH}" \ gcr.io/${gcpProject}/chat-bot-server ``` diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 63060649..ea8732f0 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -30,6 +30,7 @@ spine { dependencies { implementation "io.spine.gcloud:spine-datastore:1.5.0" + implementation 'com.google.cloud:google-cloud-secretmanager:1.0.1' implementation 'com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9' implementation 'com.google.auth:google-auth-library-oauth2-http:0.20.0' diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java new file mode 100644 index 00000000..13b8c8b1 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java @@ -0,0 +1,57 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.cloud.secretmanager.v1.SecretVersionName; + +import java.io.IOException; +import java.nio.charset.Charset; + +/** + * Utility for accessing application secrets stored in Google Secret Manager. + */ +final class Secrets { + + @SuppressWarnings("CallToSystemGetenv") + private static final String PROJECT_ID = System.getenv("GCP_PROJECT_ID"); + private static final String TRAVIS_API_TOKEN = "TravisApiToken"; + + /** Prevents direct instantiation of the utility class. **/ + private Secrets() { + } + + /** + * Returns Travis CI API access token. + */ + static String travisToken() { + try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { + var secretVersion = SecretVersionName.of(PROJECT_ID, TRAVIS_API_TOKEN, "latest"); + var secret = client.accessSecretVersion(secretVersion) + .getPayload() + .getData() + .toString(Charset.defaultCharset()); + return secret; + } catch (IOException e) { + throw new RuntimeException("Unable to retrieve Travis API key.", e); + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index b0861c53..c310a182 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -49,10 +49,17 @@ public final class TravisClient { /** * Creates a new Travis client with the specified API token. */ - public TravisClient(String token) { + private TravisClient(String token) { apiToken = token; } + /** + * Creates a new Travis client with the default secure Travis token. + */ + public static TravisClient defaultTravisClient() { + return new TravisClient(Secrets.travisToken()); + } + /** * Queries Travis CI build statuses for a repository determined by the supplied repository slug. */ @@ -60,7 +67,7 @@ public BuildsResponse queryBuildsFor(String repoSlug) { var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); var repoBuilds = "/repo/" + encodedSlug - + "/builds?limit=1&branch.name=master?include=build.commit"; + + "/builds?limit=1&branch.name=master&include=build.commit"; var request = apiRequest(repoBuilds, apiToken); try { var result = CLIENT.send(request, jsonBodyHandler(BuildsResponse.class)); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index 892c7660..ca5b6c4a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -21,7 +21,6 @@ package io.spine.chatbot.server.github; import io.spine.base.Time; -import io.spine.chatbot.api.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; @@ -35,12 +34,14 @@ import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; +import static io.spine.chatbot.api.TravisClient.defaultTravisClient; + final class RepositoryBuildProcess extends ProcessManager { @Assign BuildStateChanged handle(CheckRepositoryBuild c) { - var travis = new TravisClient(""); + var travis = defaultTravisClient(); var builds = travis.queryBuildsFor(id().getValue()) .getBuildsList(); if (builds.isEmpty()) { From ce6ff9f07d3d16bfa1d21ab080df5a5acda404f0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 10 Jun 2020 17:57:27 +0300 Subject: [PATCH 086/492] Add ability to setup the initial organization and repository within the exposed endpoint --- .../java/io/spine/chatbot/InitController.java | 41 +++++++++++++ .../spine/chatbot/client/ChatBotClient.java | 58 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/InitController.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java new file mode 100644 index 00000000..0d7d52e0 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -0,0 +1,41 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.spine.chatbot.client.ChatBotClient; +import io.spine.logging.Logging; + +/** + * A REST controller for handling initialization of the application state. + */ +@Controller("/init") +public class InitController implements Logging { + + @Get + public String initState() { + _info().log("Performing initial application state initialization."); + var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); + client.initializeDefaults(); + return "Successfully initialized"; + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java index a2e5d0a9..690050f3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -22,16 +22,26 @@ import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.base.CommandMessage; +import io.spine.base.EventMessage; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.github.repository.event.RepositoryRegistered; import io.spine.client.Client; import io.spine.client.ClientRequest; import io.spine.client.Subscription; import java.util.Collection; +import java.util.concurrent.CountDownLatch; import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; +import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; +import static io.spine.net.Urls.urlOfSpec; public final class ChatBotClient { @@ -81,4 +91,52 @@ public ImmutableList listRepositories() { .collect(toImmutableList()); return result; } + + /** + * Performs initialization of the entities that are monitored by the ChatBot + * by default. + */ + public void initializeDefaults() { + var spineOrgId = newOrganizationId("SpineEventEngine"); + var registerSpineOrg = RegisterOrganization + .newBuilder() + .setName("Spine Event Engine") + .setWebsiteUrl(urlOfSpec("https://spine.io/")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine")) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine")) + .setId(spineOrgId) + .setGoogleChatSpace("spaces/AAAAnLxnh_o") + .vBuild(); + postSyncCommand(registerSpineOrg, OrganizationRegistered.class); + var registerSpineBase = RegisterRepository + .newBuilder() + .setOrganization(spineOrgId) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) + .setId(newRepositoryId("SpineEventEngine/base")) + .setName("Spine Event Engine Base") + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) + .vBuild(); + postSyncCommand(registerSpineBase, RepositoryRegistered.class); + } + + private void + postSyncCommand(CommandMessage command, Class expectedOutcome) { + postSyncCommand(command, expectedOutcome, 1); + } + + private void + postSyncCommand(CommandMessage command, Class expectedOutcome, int expectedEvents) { + var latch = new CountDownLatch(expectedEvents); + var subscriptions = client + .asGuest() + .command(command) + .observe(expectedOutcome, event -> latch.countDown()) + .post(); + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException("Processing of command failed. Command: " + command, e); + } + subscriptions.forEach(this::cancelSubscription); + } } From 427836ada8b88b3791e19d91420f76a02e20e673 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 11:07:59 +0300 Subject: [PATCH 087/492] Configure dedicate delivery for tests and prod --- .../chatbot/ChatBotServerEnvironment.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index 840294a6..dd2d1456 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -24,14 +24,18 @@ import io.spine.base.Environment; import io.spine.server.ServerEnvironment; import io.spine.server.delivery.Delivery; +import io.spine.server.delivery.UniformAcrossAllShards; import io.spine.server.storage.StorageFactory; import io.spine.server.storage.datastore.DatastoreStorageFactory; +import io.spine.server.storage.datastore.DsShardedWorkRegistry; import io.spine.server.storage.memory.InMemoryStorageFactory; import io.spine.server.transport.memory.InMemoryTransportFactory; /** ChatBot server environment definition. **/ final class ChatBotServerEnvironment { + private static final int NUMBER_OF_SHARDS = 50; + /** * Prevents instantiation of this utility class. */ @@ -40,16 +44,32 @@ private ChatBotServerEnvironment() { /** Initializes {@link ServerEnvironment} for ChatBot. **/ static void initializeEnvironment() { - ServerEnvironment se = ServerEnvironment.instance(); - StorageFactory storageFactory = storageFactory(); + var se = ServerEnvironment.instance(); + var environment = Environment.instance(); + StorageFactory storageFactory = newStorageFactory(environment); se.configureStorage(storageFactory); se.configureTransport(InMemoryTransportFactory.newInstance()); - se.configureDelivery(Delivery.localAsync()); + se.configureDelivery(newDelivery(environment, storageFactory)); + } + + private static Delivery newDelivery(Environment environment, StorageFactory storageFactory) { + if (environment.isProduction()) { + var dsStorageFactory = (DatastoreStorageFactory) storageFactory; + var workRegistry = new DsShardedWorkRegistry(dsStorageFactory); + var inboxStorage = dsStorageFactory.createInboxStorage(false); + var delivery = Delivery + .newBuilder() + .setStrategy(UniformAcrossAllShards.forNumber(NUMBER_OF_SHARDS)) + .setWorkRegistry(workRegistry) + .setInboxStorage(inboxStorage) + .build(); + return delivery; + } + return Delivery.local(); } - private static StorageFactory storageFactory() { - if (Environment.instance() - .isProduction()) { + private static StorageFactory newStorageFactory(Environment environment) { + if (environment.isProduction()) { var datastore = DatastoreOptions.getDefaultInstance() .getService(); return DatastoreStorageFactory From 113dcb95c66c5f52d169ab92b760848e3034eaf0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 11:11:37 +0300 Subject: [PATCH 088/492] Add custom nullables configs --- .idea/misc.xml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .idea/misc.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..ae47d10d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,39 @@ + + + + + + + + + + \ No newline at end of file From 788de2fb04e256f703b77394700c44b0dae52c25 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 11:28:16 +0300 Subject: [PATCH 089/492] Drop unused org controller --- .../chatbot/OrganizationsController.java | 44 -------------- .../chatbot/OrganizationsControllerTest.java | 57 ------------------- 2 files changed, 101 deletions(-) delete mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java delete mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java deleted file mode 100644 index fe90cbb5..00000000 --- a/google-chat-bot/src/main/java/io/spine/chatbot/OrganizationsController.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.chatbot; - -import com.google.common.collect.ImmutableList; -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Get; -import io.spine.chatbot.github.organization.Organization; -import io.spine.client.Client; - -import static io.spine.chatbot.Application.SERVER_NAME; - -@Controller("/organizations") -public class OrganizationsController { - - @Get - public ImmutableList index() { - Client client = Client - .inProcess(SERVER_NAME) - .build(); - ImmutableList result = client.asGuest() - .select(Organization.class) - .run(); - return result; - } -} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java deleted file mode 100644 index 280cb550..00000000 --- a/google-chat-bot/src/test/java/io/spine/chatbot/OrganizationsControllerTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.chatbot; - -import io.micronaut.http.HttpRequest; -import io.micronaut.http.client.HttpClient; -import io.micronaut.http.client.annotation.Client; -import io.micronaut.runtime.server.EmbeddedServer; -import io.micronaut.test.annotation.MicronautTest; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import javax.inject.Inject; - -import static io.spine.chatbot.Application.initializeSpine; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@MicronautTest -final class OrganizationsControllerTest { - - @Inject - EmbeddedServer server; - - @Inject - @Client("/") - HttpClient client; - - @BeforeAll - static void setupServer() { - initializeSpine(); - } - - @Test - void testFunction() { - String actual = client.toBlocking() - .retrieve(HttpRequest.GET("/organizations")); - assertEquals("[]", actual); - } -} From 11af9c216f1909ab3f5ee940f0307b841d3bf612 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 13:26:11 +0300 Subject: [PATCH 090/492] Add Pubsub protos --- google-chat-bot/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index ea8732f0..09944303 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -28,9 +28,9 @@ spine { } dependencies { - implementation "io.spine.gcloud:spine-datastore:1.5.0" implementation 'com.google.cloud:google-cloud-secretmanager:1.0.1' + implementation 'com.google.api.grpc:proto-google-cloud-pubsub-v1:1.89.0' implementation 'com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9' implementation 'com.google.auth:google-auth-library-oauth2-http:0.20.0' From e1120632ee5c346d9faa34943e0bd1a888aae918 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 13:26:23 +0300 Subject: [PATCH 091/492] Add Pubsub push notification proto --- .../proto/google/pubsub/v1/pubsub_push.proto | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto new file mode 100644 index 00000000..f2d28498 --- /dev/null +++ b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package google.pubsub.v1; + +option java_multiple_files = true; +option java_outer_classname = "PubsubPushProto"; +option java_package = "com.google.pubsub.v1"; + +import "google/pubsub/v1/pubsub.proto"; + +// Pubsub push message notification. +message PubsubPushNotification { + + // Pubsub message. + PubsubMessage message = 1; + + // The name of the Pubsub subscription that pushed the current notification. + // Format is `projects/{project}/subscriptions/{subscription}`. + string subscription = 2; +} From b4ec02b460342a76c47ba4c463d0c5ad5f2fcc96 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 13:27:00 +0300 Subject: [PATCH 092/492] Define protos for Google Chat incoming messages --- .../incoming/incoming_chat_messages.proto | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto new file mode 100644 index 00000000..8aa54f30 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -0,0 +1,99 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat.incoming; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.incoming"; +option java_outer_classname = "IncomingChatMessagesProto"; +option java_multiple_files = true; + +// Denotes that a message was created in the space. +message ChatEvent { + + EventType type = 1; + + string event_time = 2; + + Space space = 3; + + User user = 4; +} + +message Message { + string name = 1; + + User sender = 2; + string create_time = 3; + string text = 4; + string argumentText = 5; + Thread thread = 6; + + message Thread { + string name = 1; + } + + repeated Annotation annotations = 7; + + message Annotation { + uint32 length = 1; + uint32 start_index = 2; + + UserMention user_mention = 3; + + message UserMention { + string type = 1; + User user = 2; + } + string type = 4; + } +} + + +message Space { + string name = 1; + string display_name = 2; + SpaceType type = 3; +} + +message User { + string name = 1; + string displayName = 2; + string avatarUrl = 3; + string email = 4; + string type = 5; +} + +enum SpaceType { + ST_UNKNOWN = 0; + ROOM = 1; + DM = 2; +} + +enum EventType { + ET_UNKNOWN = 0; + ADDED_TO_SPACE = 1; + REMOVED_FROM_SPACE = 2; + MESSAGE = 3; +} From 942982551ad8534a07cef71ee8e40ea771e5fa47 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 13:27:20 +0300 Subject: [PATCH 093/492] Create custom Pubsub push notification JSON deserializer --- .../java/io/spine/chatbot/BeanFactory.java | 21 +++++++++++++ .../PubsubPushNotificationDeserializer.java | 30 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java new file mode 100644 index 00000000..c1b86e2c --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -0,0 +1,21 @@ +package io.spine.chatbot; + +import io.micronaut.context.annotation.Bean; +import io.micronaut.context.annotation.Factory; +import io.spine.chatbot.jackson.PubsubPushNotificationDeserializer; + +import javax.inject.Singleton; + +/** + * Creates Micronaut context bean definitions. + */ +@Factory +public class BeanFactory { + + /** Registers Pubsub push notification Jackson deserializer. **/ + @Singleton + @Bean + public PubsubPushNotificationDeserializer pubsubDeserializer() { + return new PubsubPushNotificationDeserializer(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java b/google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java new file mode 100644 index 00000000..5434b8a7 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java @@ -0,0 +1,30 @@ +package io.spine.chatbot.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.google.pubsub.v1.PubsubPushNotification; +import io.spine.json.Json; + +import java.io.IOException; + +/** + * Spine-based {@link PubsubPushNotification} Jackson deserializer. + */ +public final class PubsubPushNotificationDeserializer extends JsonDeserializer { + + /** + * Deserializes {@link PubsubPushNotification} JSON string into a Protobuf message. + */ + @Override + public PubsubPushNotification deserialize(JsonParser parser, DeserializationContext ctxt) { + try { + var protoJson = parser.readValueAsTree() + .toString(); + var result = Json.fromJson(protoJson, PubsubPushNotification.class); + return result; + } catch (IOException e) { + throw new RuntimeException("Unable to deserialize PubsubPushNotification json.", e); + } + } +} From a75a74e0248e60ef65de672873b9d590624d6147 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 13:28:43 +0300 Subject: [PATCH 094/492] Add endpoint for handling Google Chat message notifications --- .../chatbot/IncomingEventsController.java | 37 ++++++ .../chatbot/IncomingEventsControllerTest.java | 115 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java new file mode 100644 index 00000000..74913169 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -0,0 +1,37 @@ +package io.spine.chatbot; + +import com.google.protobuf.ByteString; +import com.google.protobuf.util.JsonFormat; +import com.google.pubsub.v1.PubsubPushNotification; +import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Body; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Post; +import io.spine.chatbot.google.chat.incoming.ChatEvent; +import io.spine.json.Json; +import io.spine.logging.Logging; + +import java.util.Base64; + +/** + * A REST controller for handling incoming PubSub events from Google Chat users. + */ +@Controller("/chat") +public class IncomingEventsController implements Logging { + + /** Requests build status checks for registered listRepositories. **/ + @Post(value = "/incoming/event", consumes = MediaType.APPLICATION_JSON) + public String checkRepositoryStatuses(@Body PubsubPushNotification pushNotification) { + var message = pushNotification.getMessage(); + var chatEventJson = decodeBase64Json(message.getData()); + ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); + _debug().log("Received a new Chat event: %s", chatEvent); + return "OK"; + } + + private static String decodeBase64Json(ByteString encoded) { + var decodedBytes = Base64.getDecoder() + .decode(encoded.toByteArray()); + return new String(decodedBytes); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java new file mode 100644 index 00000000..4c16c787 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -0,0 +1,115 @@ +package io.spine.chatbot; + +import com.google.protobuf.ByteString; +import com.google.pubsub.v1.PubsubMessage; +import com.google.pubsub.v1.PubsubPushNotification; +import io.micronaut.http.MediaType; +import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.runtime.server.EmbeddedServer; +import io.micronaut.test.annotation.MicronautTest; +import io.spine.json.Json; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import javax.inject.Inject; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +import static io.micronaut.http.HttpRequest.POST; +import static io.spine.chatbot.Application.initializeSpine; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@DisplayName("IncomingEventsController should") +@MicronautTest +final class IncomingEventsControllerTest { + + @Inject + EmbeddedServer server; + + @Inject + @Client("/") + HttpClient client; + + @BeforeAll + static void setupServer() { + initializeSpine(); + } + + @Test + @DisplayName("receive and decode a pubsub message with Google Chat event") + void receiveAndDecode() { + //TODO:2020-06-11:ysergiichuk: make sure we handle serialization/deserialization of the + // chat events properly. Looks like the JSON below could not be deserialized due to internal + // proto issue + var pubsubMessage = PubsubMessage + .newBuilder() + .setMessageId("129y418y4houfhiuehwr") + .setData(base64Encode(CHAT_MESSAGE_EVENT)) + .build(); + var pushNotification = PubsubPushNotification + .newBuilder() + .setMessage(pubsubMessage) + .setSubscription("projects/test-project/subscriptions/test-subscription") + .vBuild(); + var request = POST("/chat/incoming/event", Json.toJson(pushNotification)) + .contentType(MediaType.APPLICATION_JSON); + String actual = client.toBlocking() + .retrieve(request); + assertEquals("success", actual); + } + + private static ByteString base64Encode(String value) { + var encoder = Base64.getEncoder(); + return ByteString.copyFrom(encoder.encode(value.getBytes(StandardCharsets.UTF_8))); + } + + private static final String CHAT_MESSAGE_EVENT = "" + + "{\n" + + " \"type\": \"MESSAGE\",\n" + + " \"eventTime\": \"2017-03-02T19:02:59.910959Z\",\n" + + " \"space\": {\n" + + " \"name\": \"spaces/AAAAAAAAAAA\",\n" + + " \"displayName\": \"Chuck Norris Discussion Room\",\n" + + " \"type\": \"ROOM\"\n" + + " },\n" + + " \"message\": {\n" + + " \"name\": \"spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC\",\n" + + " \"sender\": {\n" + + " \"name\": \"users/12345678901234567890\",\n" + + " \"displayName\": \"Chuck Norris\",\n" + + " \"avatarUrl\": \"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + + " \"email\": \"chuck@example.com\"\n" + + " },\n" + + " \"createTime\": \"2017-03-02T19:02:59.910959Z\",\n" + + " \"text\": \"@TestBot Violence is my last option.\",\n" + + " \"argumentText\": \" Violence is my last option.\",\n" + + " \"thread\": {\n" + + " \"name\": \"spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB\"\n" + + " },\n" + + " \"annotations\": [\n" + + " {\n" + + " \"length\": 8,\n" + + " \"startIndex\": 0,\n" + + " \"userMention\": {\n" + + " \"type\": \"MENTION\",\n" + + " \"user\": {\n" + + " \"avatarUrl\": \"https://.../avatar.png\",\n" + + " \"displayName\": \"TestBot\",\n" + + " \"name\": \"users/1234567890987654321\",\n" + + " \"type\": \"BOT\"\n" + + " }\n" + + " },\n" + + " \"type\": \"USER_MENTION\"\n" + + " }\n" + + " ],\n" + + " },\n" + + " \"user\": {\n" + + " \"name\": \"users/12345678901234567890\",\n" + + " \"displayName\": \"Chuck Norris\",\n" + + " \"avatarUrl\": \"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + + " \"email\": \"chuck@example.com\"\n" + + " }\n" + + "}"; +} From 339719d68c7ad9238416d00120ca4c38d50eed08 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 19:28:26 +0300 Subject: [PATCH 095/492] Fix test JSON --- .../chatbot/IncomingEventsControllerTest.java | 95 +++++++++++-------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 4c16c787..3c5ef2ee 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot; import com.google.protobuf.ByteString; @@ -40,9 +60,6 @@ static void setupServer() { @Test @DisplayName("receive and decode a pubsub message with Google Chat event") void receiveAndDecode() { - //TODO:2020-06-11:ysergiichuk: make sure we handle serialization/deserialization of the - // chat events properly. Looks like the JSON below could not be deserialized due to internal - // proto issue var pubsubMessage = PubsubMessage .newBuilder() .setMessageId("129y418y4houfhiuehwr") @@ -57,7 +74,7 @@ void receiveAndDecode() { .contentType(MediaType.APPLICATION_JSON); String actual = client.toBlocking() .retrieve(request); - assertEquals("success", actual); + assertEquals("OK", actual); } private static ByteString base64Encode(String value) { @@ -67,49 +84,49 @@ private static ByteString base64Encode(String value) { private static final String CHAT_MESSAGE_EVENT = "" + "{\n" + - " \"type\": \"MESSAGE\",\n" + - " \"eventTime\": \"2017-03-02T19:02:59.910959Z\",\n" + - " \"space\": {\n" + - " \"name\": \"spaces/AAAAAAAAAAA\",\n" + - " \"displayName\": \"Chuck Norris Discussion Room\",\n" + - " \"type\": \"ROOM\"\n" + + " \"type\":\"MESSAGE\",\n" + + " \"eventTime\":\"2017-03-02T19:02:59.910959Z\",\n" + + " \"space\":{\n" + + " \"name\":\"spaces/AAAAAAAAAAA\",\n" + + " \"displayName\":\"Chuck Norris Discussion Room\",\n" + + " \"type\":\"ROOM\"\n" + " },\n" + - " \"message\": {\n" + - " \"name\": \"spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC\",\n" + - " \"sender\": {\n" + - " \"name\": \"users/12345678901234567890\",\n" + - " \"displayName\": \"Chuck Norris\",\n" + - " \"avatarUrl\": \"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + - " \"email\": \"chuck@example.com\"\n" + + " \"message\":{\n" + + " \"name\":\"spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC\",\n" + + " \"sender\":{\n" + + " \"name\":\"users/12345678901234567890\",\n" + + " \"displayName\":\"Chuck Norris\",\n" + + " \"avatarUrl\":\"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + + " \"email\":\"chuck@example.com\"\n" + " },\n" + - " \"createTime\": \"2017-03-02T19:02:59.910959Z\",\n" + - " \"text\": \"@TestBot Violence is my last option.\",\n" + - " \"argumentText\": \" Violence is my last option.\",\n" + - " \"thread\": {\n" + - " \"name\": \"spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB\"\n" + + " \"createTime\":\"2017-03-02T19:02:59.910959Z\",\n" + + " \"text\":\"@TestBot Violence is my last option.\",\n" + + " \"argumentText\":\" Violence is my last option.\",\n" + + " \"thread\":{\n" + + " \"name\":\"spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB\"\n" + " },\n" + - " \"annotations\": [\n" + + " \"annotations\":[\n" + " {\n" + - " \"length\": 8,\n" + - " \"startIndex\": 0,\n" + - " \"userMention\": {\n" + - " \"type\": \"MENTION\",\n" + - " \"user\": {\n" + - " \"avatarUrl\": \"https://.../avatar.png\",\n" + - " \"displayName\": \"TestBot\",\n" + - " \"name\": \"users/1234567890987654321\",\n" + - " \"type\": \"BOT\"\n" + + " \"length\":8,\n" + + " \"startIndex\":0,\n" + + " \"userMention\":{\n" + + " \"type\":\"MENTION\",\n" + + " \"user\":{\n" + + " \"avatarUrl\":\"https://.../avatar.png\",\n" + + " \"displayName\":\"TestBot\",\n" + + " \"name\":\"users/1234567890987654321\",\n" + + " \"type\":\"BOT\"\n" + " }\n" + " },\n" + - " \"type\": \"USER_MENTION\"\n" + + " \"type\":\"USER_MENTION\"\n" + " }\n" + - " ],\n" + + " ]\n" + " },\n" + - " \"user\": {\n" + - " \"name\": \"users/12345678901234567890\",\n" + - " \"displayName\": \"Chuck Norris\",\n" + - " \"avatarUrl\": \"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + - " \"email\": \"chuck@example.com\"\n" + + " \"user\":{\n" + + " \"name\":\"users/12345678901234567890\",\n" + + " \"displayName\":\"Chuck Norris\",\n" + + " \"avatarUrl\":\"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + + " \"email\":\"chuck@example.com\"\n" + " }\n" + "}"; } From ed0088b5dc9d4ae92d9f67d659c8a2cb378a397d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 11 Jun 2020 19:28:44 +0300 Subject: [PATCH 096/492] Add message field --- .../incoming/incoming_chat_messages.proto | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 8aa54f30..b3c7a353 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -38,7 +38,9 @@ message ChatEvent { Space space = 3; - User user = 4; + Message message = 4; + + User user = 5; } message Message { @@ -93,7 +95,16 @@ enum SpaceType { enum EventType { ET_UNKNOWN = 0; - ADDED_TO_SPACE = 1; - REMOVED_FROM_SPACE = 2; - MESSAGE = 3; + + // A message was sent in a room or direct message. + MESSAGE = 1; + + // The bot was added to a room or DM. + ADDED_TO_SPACE = 2; + + // The bot was removed from a room or DM. + REMOVED_FROM_SPACE = 3; + + // The bot's interactive card was clicked. + CARD_CLICKED = 4; } From b083ccc1d9ecb41e31491f1835ba84b08f3f0016 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 13:42:43 +0300 Subject: [PATCH 097/492] handle adding the bot the the space --- .../chatbot/IncomingEventsController.java | 55 ++++++++++++++++++- .../spine/chatbot/client/ChatBotClient.java | 5 +- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 74913169..7e644c59 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -1,13 +1,38 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot; import com.google.protobuf.ByteString; -import com.google.protobuf.util.JsonFormat; import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; +import io.spine.chatbot.client.ChatBotClient; +import io.spine.chatbot.google.chat.command.RegisterSpace; +import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.google.chat.incoming.ChatEvent; +import io.spine.chatbot.google.chat.incoming.Space; +import io.spine.chatbot.google.chat.incoming.SpaceType; +import io.spine.chatbot.server.google.chat.Identifiers; import io.spine.json.Json; import io.spine.logging.Logging; @@ -25,10 +50,38 @@ public String checkRepositoryStatuses(@Body PubsubPushNotification pushNotificat var message = pushNotification.getMessage(); var chatEventJson = decodeBase64Json(message.getData()); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); + var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); + switch (chatEvent.getType()) { + case MESSAGE: + break; + case ADDED_TO_SPACE: + onBotAddedToSpace(chatEvent.getSpace(), client); + break; + case REMOVED_FROM_SPACE: + case CARD_CLICKED: + case UNRECOGNIZED: + case ET_UNKNOWN: + _warn().log("Unsupported chat event type received: %s", chatEvent.getType()); + break; + } _debug().log("Received a new Chat event: %s", chatEvent); return "OK"; } + private static void onBotAddedToSpace(Space space, ChatBotClient client) { + var registerSpace = RegisterSpace + .newBuilder() + .setDisplayName(space.getDisplayName()) + .setThreaded(isThreaded(space)) + .setId(Identifiers.newSpaceId(space.getName())) + .vBuild(); + client.postSyncCommand(registerSpace, SpaceRegistered.class); + } + + private static boolean isThreaded(Space space) { + return space.getType() == SpaceType.ROOM; + } + private static String decodeBase64Json(ByteString encoded) { var decodedBytes = Base64.getDecoder() .decode(encoded.toByteArray()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java index 690050f3..820fb5b9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -119,7 +119,10 @@ public void initializeDefaults() { postSyncCommand(registerSpineBase, RepositoryRegistered.class); } - private void + /** + * Posts a command and waits synchronously till the expected outcome event is published. + */ + public void postSyncCommand(CommandMessage command, Class expectedOutcome) { postSyncCommand(command, expectedOutcome, 1); } From 16a0ac3f6da2f1da68bb02d555e1a9e52967454f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 14:39:00 +0300 Subject: [PATCH 098/492] add gradle build deps --- buildSrc/build.gradle.kts | 30 ++++++ buildSrc/src/main/kotlin/deps.kt | 159 +++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/deps.kt diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..94225f67 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +plugins { + // Use Kotlin for `buildSrc`. + // https://kotlinlang.org/docs/reference/using-gradle.html#targeting-the-jvm + kotlin("jvm").version("1.3.72") +} + +repositories { + mavenLocal() + jcenter() +} diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt new file mode 100644 index 00000000..d83d31ed --- /dev/null +++ b/buildSrc/src/main/kotlin/deps.kt @@ -0,0 +1,159 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.gradle.api.artifacts.ConfigurationContainer + + +// Specific repositories. +object Repos { + + const val sonatypeSnapshots: String = "https://oss.sonatype.org/content/repositories/snapshots" + const val gradlePlugins = "https://plugins.gradle.org/m2/" +} + +object Versions { + const val checkerFramework = "3.3.0" + const val errorProne = "2.4.0" + const val pmd = "6.20.0" + const val checkstyle = "8.29" + const val findBugs = "3.0.2" + const val guava = "29.0-jre" + const val grpc = "1.28.1" + const val flogger = "0.5.1" + const val junit5 = "5.6.2" + const val junitPlatform = "1.6.2" + const val truth = "1.0.1" + const val micronaut = "2.0.0.M3" + const val spineGcloud = "1.5.0" + const val googleSecretManager = "1.0.1" + const val googlePubsubProto = "1.89.0" + const val googleChat = "v1-rev20200502-1.30.9" + const val googleAuth = "0.20.0" + + const val licensePlugin = "1.13" + const val errorPronePlugin = "1.2.1" + const val aptPluginVersion = "0.21" + const val shadowPluginVersion = "5.2.0" + const val jibPluginVersion = "2.4.0" + const val spineBootstrapPluginVersion = "1.5.17" + const val propertiesPluginVersion = "1.5.1" +} + +object GradlePlugins { + const val apt = "net.ltgt.gradle:gradle-apt-plugin::${Versions.aptPluginVersion}" + const val shadow = "com.github.jengelman.gradle.plugins:shadow:${Versions.shadowPluginVersion}" + const val jib = "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:${Versions.jibPluginVersion}" + const val properties = "net.saliman:gradle-properties-plugin:${Versions.propertiesPluginVersion}" + const val spineBootstrap = "io.spine.tools:spine-bootstrap:${Versions.spineBootstrapPluginVersion}" + const val errorProne = "net.ltgt.gradle:gradle-errorprone-plugin:${Versions.errorPronePlugin}" + const val licenseReport = "com.github.jk1:gradle-license-report:${Versions.licensePlugin}" +} + +object Build { + val errorProneAnnotations = listOf( + "com.google.errorprone:error_prone_annotations:${Versions.errorProne}", + "com.google.errorprone:error_prone_type_annotations:${Versions.errorProne}" + ) + const val errorProneCheckApi = "com.google.errorprone:error_prone_check_api:${Versions.errorProne}" + const val errorProneCore = "com.google.errorprone:error_prone_core:${Versions.errorProne}" + const val errorProneTestHelpers = "com.google.errorprone:error_prone_test_helpers:${Versions.errorProne}" + const val checkerAnnotations = "org.checkerframework:checker-qual:${Versions.checkerFramework}" + val checkerDataflow = listOf( + "org.checkerframework:dataflow:${Versions.checkerFramework}", + "org.checkerframework:javacutil:${Versions.checkerFramework}" + ) + const val jsr305Annotations = "com.google.code.findbugs:jsr305:${Versions.findBugs}" + const val guava = "com.google.guava:guava:${Versions.guava}" + const val flogger = "com.google.flogger:flogger:${Versions.flogger}" + val ci = "true".equals(System.getenv("CI")) + val gradlePlugins = GradlePlugins +} + +object Micronaut { + const val bom = "io.micronaut:micronaut-bom:${Versions.micronaut}" + const val inject = "io.micronaut:micronaut-inject" + const val injectJava = "io.micronaut:micronaut-inject-java" + const val validation = "io.micronaut:micronaut-validation" + const val runtime = "io.micronaut:micronaut-runtime" + const val netty = "io.micronaut:micronaut-http-server-netty" + const val testJUnit5 = "io.micronaut.test:micronaut-test-junit5" +} + +object Grpc { + const val core = "io.grpc:grpc-core:${Versions.grpc}" + const val stub = "io.grpc:grpc-stub:${Versions.grpc}" + const val okHttp = "io.grpc:grpc-okhttp:${Versions.grpc}" + const val protobuf = "io.grpc:grpc-protobuf:${Versions.grpc}" + const val netty = "io.grpc:grpc-netty:${Versions.grpc}" + const val nettyShaded = "io.grpc:grpc-netty-shaded:${Versions.grpc}" + const val context = "io.grpc:grpc-context:${Versions.grpc}" +} + +object Runtime { + + val flogger = Flogger + + object Flogger { + const val systemBackend = "com.google.flogger:flogger-system-backend:${Versions.flogger}" + const val log4J = "com.google.flogger:flogger-log4j:${Versions.flogger}" + const val slf4J = "com.google.flogger:slf4j-backend-factory:${Versions.flogger}" + } +} + +object Test { + val junit5Api = listOf( + "org.junit.jupiter:junit-jupiter-api:${Versions.junit5}", + "org.junit.jupiter:junit-jupiter-params:${Versions.junit5}" + ) + const val junit5Runner = "org.junit.jupiter:junit-jupiter-engine:${Versions.junit5}" + const val guavaTestlib = "com.google.guava:guava-testlib:${Versions.guava}" + val truth = listOf( + "com.google.truth:truth:${Versions.truth}", + "com.google.truth.extensions:truth-java8-extension:${Versions.truth}", + "com.google.truth.extensions:truth-proto-extension:${Versions.truth}" + ) +} + +object Deps { + val build = Build + val grpc = Grpc + val runtime = Runtime + val test = Test + val versions = Versions +} + +object DependencyResolution { + + fun forceConfiguration(configurations: ConfigurationContainer) { + configurations.all { config -> + config.resolutionStrategy { strategy -> + strategy.force( + Deps.build.errorProneAnnotations, + Deps.build.jsr305Annotations, + Deps.build.checkerAnnotations, + Deps.build.guava, + Deps.test.guavaTestlib, + Deps.test.truth, + Deps.test.junit5Api + ) + } + } + } +} From d3c4f72b08de5663366b32e17d1a3b1a76044d2b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:40:16 +0300 Subject: [PATCH 099/492] Add version.gradle --- version.gradle.kts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 version.gradle.kts diff --git a/version.gradle.kts b/version.gradle.kts new file mode 100644 index 00000000..3d303e84 --- /dev/null +++ b/version.gradle.kts @@ -0,0 +1,25 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * The version of the application. + */ + +val botVersion: String by extra("0.0.1") \ No newline at end of file From bf720123329344da322a037ea0a485674904412b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:40:26 +0300 Subject: [PATCH 100/492] migrate settings to kotlin --- settings.gradle => settings.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename settings.gradle => settings.gradle.kts (97%) diff --git a/settings.gradle b/settings.gradle.kts similarity index 97% rename from settings.gradle rename to settings.gradle.kts index 3cab8db6..1a860846 100644 --- a/settings.gradle +++ b/settings.gradle.kts @@ -19,5 +19,4 @@ */ rootProject.name = "chat-bot" -include 'google-chat-bot' - +include("google-chat-bot") From 40b25e0417ad3825c79da78995835eb985106d87 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:40:43 +0300 Subject: [PATCH 101/492] upgrade v6.4.1 --- gradle/wrapper/gradle-wrapper.properties | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 42176947..f7ecde68 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,25 @@ -#Tue May 26 14:15:06 EEST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip +# +# Copyright 2020, TeamDev. All rights reserved. +# +# Redistribution and use in source and/or binary forms, with or without +# modification, must retain the above copyright notice and the following +# disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +#Mon Jun 15 15:39:45 EEST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From 2ad4234a107c98c8a125fea13cb4ef918772f5bd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:41:20 +0300 Subject: [PATCH 102/492] Update internal plugins --- buildSrc/build.gradle.kts | 18 ++++++++++--- buildSrc/src/main/kotlin/deps.kt | 44 +++++++++----------------------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 94225f67..b6696305 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -19,12 +19,24 @@ */ plugins { - // Use Kotlin for `buildSrc`. - // https://kotlinlang.org/docs/reference/using-gradle.html#targeting-the-jvm - kotlin("jvm").version("1.3.72") + `kotlin-dsl` } repositories { mavenLocal() jcenter() + gradlePluginPortal() +} + +dependencies { + implementation("net.ltgt.gradle:gradle-errorprone-plugin:1.2.1") + implementation("net.ltgt.gradle:gradle-apt-plugin:0.21") + implementation("com.github.jengelman.gradle.plugins:shadow:5.2.0") + implementation("gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.4.0") + implementation("io.spine.tools:spine-bootstrap:1.5.17") + implementation("net.saliman:gradle-properties-plugin:1.5.1") +} + +kotlinDslPluginOptions { + experimentalWarning.set(false) } diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index d83d31ed..d06fb910 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -18,8 +18,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.gradle.api.artifacts.ConfigurationContainer - // Specific repositories. object Repos { @@ -47,21 +45,21 @@ object Versions { const val googleChat = "v1-rev20200502-1.30.9" const val googleAuth = "0.20.0" - const val licensePlugin = "1.13" + const val licensePlugin = "1.14" const val errorPronePlugin = "1.2.1" - const val aptPluginVersion = "0.21" - const val shadowPluginVersion = "5.2.0" - const val jibPluginVersion = "2.4.0" - const val spineBootstrapPluginVersion = "1.5.17" - const val propertiesPluginVersion = "1.5.1" + const val aptPlugin = "0.21" + const val shadowPlugin = "5.2.0" + const val jibPlugin = "2.4.0" + const val spineBootstrapPlugin = "1.5.17" + const val propertiesPlugin = "1.5.1" } object GradlePlugins { - const val apt = "net.ltgt.gradle:gradle-apt-plugin::${Versions.aptPluginVersion}" - const val shadow = "com.github.jengelman.gradle.plugins:shadow:${Versions.shadowPluginVersion}" - const val jib = "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:${Versions.jibPluginVersion}" - const val properties = "net.saliman:gradle-properties-plugin:${Versions.propertiesPluginVersion}" - const val spineBootstrap = "io.spine.tools:spine-bootstrap:${Versions.spineBootstrapPluginVersion}" + const val apt = "net.ltgt.gradle:gradle-apt-plugin:${Versions.aptPlugin}" + const val shadow = "com.github.jengelman.gradle.plugins:shadow:${Versions.shadowPlugin}" + const val jib = "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:${Versions.jibPlugin}" + const val properties = "net.saliman:gradle-properties-plugin:${Versions.propertiesPlugin}" + const val spineBootstrap = "io.spine.tools:spine-bootstrap:${Versions.spineBootstrapPlugin}" const val errorProne = "net.ltgt.gradle:gradle-errorprone-plugin:${Versions.errorPronePlugin}" const val licenseReport = "com.github.jk1:gradle-license-report:${Versions.licensePlugin}" } @@ -84,6 +82,7 @@ object Build { const val flogger = "com.google.flogger:flogger:${Versions.flogger}" val ci = "true".equals(System.getenv("CI")) val gradlePlugins = GradlePlugins + val micronaut = Micronaut } object Micronaut { @@ -138,22 +137,3 @@ object Deps { val test = Test val versions = Versions } - -object DependencyResolution { - - fun forceConfiguration(configurations: ConfigurationContainer) { - configurations.all { config -> - config.resolutionStrategy { strategy -> - strategy.force( - Deps.build.errorProneAnnotations, - Deps.build.jsr305Annotations, - Deps.build.checkerAnnotations, - Deps.build.guava, - Deps.test.guavaTestlib, - Deps.test.truth, - Deps.test.junit5Api - ) - } - } - } -} From 539a7f60264d900e090d2a2078c515f5790276a4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:41:39 +0300 Subject: [PATCH 103/492] Create internal JavaConvention plugin --- .../main/kotlin/java-convention.gradle.kts | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 buildSrc/src/main/kotlin/java-convention.gradle.kts diff --git a/buildSrc/src/main/kotlin/java-convention.gradle.kts b/buildSrc/src/main/kotlin/java-convention.gradle.kts new file mode 100644 index 00000000..625e05c1 --- /dev/null +++ b/buildSrc/src/main/kotlin/java-convention.gradle.kts @@ -0,0 +1,55 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import net.ltgt.gradle.errorprone.errorprone + +plugins { + `java-library` + id("net.ltgt.errorprone") + id("net.ltgt.apt-idea") +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +dependencies { + errorprone(Deps.build.errorProneCore) + implementation(Deps.build.guava) + implementation(Deps.build.jsr305Annotations) + implementation(Deps.build.checkerAnnotations) + Deps.build.errorProneAnnotations.forEach { implementation(it) } + + testImplementation(Deps.test.guavaTestlib) + Deps.test.junit5Api.forEach { testImplementation(it) } + Deps.test.truth.forEach { testImplementation(it) } + testRuntimeOnly(Deps.test.junit5Runner) +} + +tasks.test { + useJUnitPlatform { + includeEngines("junit-jupiter") + } +} + +tasks.compileJava { + options.errorprone.disableWarningsInGeneratedCode.set(true) +} \ No newline at end of file From be1342d7dc6a3eb746947e5f98b1f296f364b749 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:42:02 +0300 Subject: [PATCH 104/492] Move bot-specific configurations and plugins to bot build script --- google-chat-bot/build.gradle | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle index 09944303..e0e4faf3 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle @@ -18,7 +18,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -apply plugin: 'io.spine.tools.gradle.bootstrap' +plugins { + id "application" + id "com.github.johnrengelman.shadow" + id "com.google.cloud.tools.jib" + id "io.spine.tools.gradle.bootstrap" +} + spine { enableJava().server() @@ -28,6 +34,23 @@ spine { } dependencies { + annotationProcessor(enforcedPlatform(Build.micronaut.bom)) + annotationProcessor(Build.micronaut.injectJava) + annotationProcessor(Build.micronaut.validation) + + compileOnly(enforcedPlatform(Build.micronaut.bom)) + + implementation(enforcedPlatform(Build.micronaut.bom)) + implementation(Build.micronaut.inject) + implementation(Build.micronaut.validation) + implementation(Build.micronaut.runtime) + implementation(Build.micronaut.netty) + implementation("javax.annotation:javax.annotation-api") + + implementation("org.apache.logging.log4j:log4j-core:2.13.3") + runtimeOnly("org.apache.logging.log4j:log4j-api:2.13.3") + runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.3") + implementation "io.spine.gcloud:spine-datastore:1.5.0" implementation 'com.google.cloud:google-cloud-secretmanager:1.0.1' implementation 'com.google.api.grpc:proto-google-cloud-pubsub-v1:1.89.0' From 5597a1297da6027d37483b3ad326d58a165a339d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 16:42:30 +0300 Subject: [PATCH 105/492] Replace groovy config with kotlin config --- build.gradle | 117 ----------------------------------------------- build.gradle.kts | 60 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 117 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 7e65003d..00000000 --- a/build.gradle +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -plugins { - id "net.ltgt.apt" version "0.21" apply false - id "com.github.johnrengelman.shadow" version "5.2.0" apply false - id 'com.google.cloud.tools.jib' version '2.3.0' apply false - id "net.saliman.properties" version "1.5.1" apply false - id 'io.spine.tools.gradle.bootstrap' version '1.5.8' apply false - id "net.ltgt.errorprone" version "1.2.1" apply false -} - -allprojects { - version "0.1" - group "io.spine" - apply plugin: "idea" - apply plugin: "net.saliman.properties" -} - -subprojects { - apply plugin: "net.ltgt.apt-idea" - apply plugin: "com.github.johnrengelman.shadow" - apply plugin: "application" - apply plugin: "com.google.cloud.tools.jib" - apply plugin: "net.ltgt.errorprone" - - repositories { - jcenter() - mavenCentral() - } - configurations { - // for dependencies that are needed for development only - developmentOnly - invoker - } - - dependencies { - errorprone "com.google.errorprone:error_prone_core:2.4.0" - annotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - annotationProcessor("io.micronaut:micronaut-inject-java") - annotationProcessor("io.micronaut:micronaut-validation") - - compileOnly(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - - implementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - implementation("io.micronaut:micronaut-inject") - implementation("io.micronaut:micronaut-validation") - implementation("io.micronaut:micronaut-runtime") - implementation("com.google.guava:guava:29.0-jre") - - implementation "io.micronaut:micronaut-http-server-netty" - implementation("javax.annotation:javax.annotation-api") - - implementation("org.apache.logging.log4j:log4j-core:2.13.3") - runtimeOnly("org.apache.logging.log4j:log4j-api:2.13.3") - runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.3") - - testAnnotationProcessor(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - testAnnotationProcessor("io.micronaut:micronaut-inject-java") - testImplementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")) - testImplementation("io.micronaut:micronaut-http-client") - testImplementation("org.junit.jupiter:junit-jupiter-api") - testImplementation("io.micronaut.test:micronaut-test-junit5") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") - } - - test.classpath += configurations.developmentOnly - - test { - useJUnitPlatform() - } - - java { - sourceCompatibility = JavaVersion.toVersion('11') - targetCompatibility = JavaVersion.toVersion('11') - } - - tasks.withType(JavaCompile) { - options.encoding = "UTF-8" - options.compilerArgs.addAll("-Xlint:unchecked", "-Xlint:deprecation") - - options.errorprone - .errorproneArgs - .addAll('-XepExcludedPaths:.*/generated/.*', - '-Xep:ClassCanBeStatic:OFF', - '-Xep:UnusedMethod:OFF', - '-Xep:UnusedVariable:OFF', - '-Xep:CheckReturnValue:OFF') - } - - tasks.withType(JavaExec) { - classpath += configurations.developmentOnly - jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote') - } - - shadowJar { - minimize() - mergeServiceFiles() - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..dc2a16c5 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,60 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import net.saliman.gradle.plugin.properties.PropertiesPlugin + +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +plugins { + idea +} + +apply(from = "version.gradle.kts") +val botVersion: String by extra + +allprojects { + apply() + apply() + + group = "io.spine" + version = botVersion +} + +subprojects { + apply() +} From 69813413c14b3f3253d898b114630e91353f611a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:08:46 +0300 Subject: [PATCH 106/492] Remove unused deps --- buildSrc/src/main/kotlin/deps.kt | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index d06fb910..88429666 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -18,14 +18,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -// Specific repositories. -object Repos { - - const val sonatypeSnapshots: String = "https://oss.sonatype.org/content/repositories/snapshots" - const val gradlePlugins = "https://plugins.gradle.org/m2/" -} - object Versions { const val checkerFramework = "3.3.0" const val errorProne = "2.4.0" @@ -93,16 +85,7 @@ object Micronaut { const val runtime = "io.micronaut:micronaut-runtime" const val netty = "io.micronaut:micronaut-http-server-netty" const val testJUnit5 = "io.micronaut.test:micronaut-test-junit5" -} - -object Grpc { - const val core = "io.grpc:grpc-core:${Versions.grpc}" - const val stub = "io.grpc:grpc-stub:${Versions.grpc}" - const val okHttp = "io.grpc:grpc-okhttp:${Versions.grpc}" - const val protobuf = "io.grpc:grpc-protobuf:${Versions.grpc}" - const val netty = "io.grpc:grpc-netty:${Versions.grpc}" - const val nettyShaded = "io.grpc:grpc-netty-shaded:${Versions.grpc}" - const val context = "io.grpc:grpc-context:${Versions.grpc}" + const val httpClient = "io.micronaut:micronaut-http-client" } object Runtime { @@ -132,7 +115,6 @@ object Test { object Deps { val build = Build - val grpc = Grpc val runtime = Runtime val test = Test val versions = Versions From 6b5d026f1155652636d72bd1dd589243ac3d8a1c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:08:56 +0300 Subject: [PATCH 107/492] Remove unused prop --- gradle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 777b84ca..2aef60d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,5 +17,4 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -micronautVersion=2.0.0.M3 gcpProject='' \ No newline at end of file From dfc57faf21774a39d47b4ff779bb491cc6a53623 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:09:13 +0300 Subject: [PATCH 108/492] Configure Java compiler and errorprone --- .../main/kotlin/java-convention.gradle.kts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/buildSrc/src/main/kotlin/java-convention.gradle.kts b/buildSrc/src/main/kotlin/java-convention.gradle.kts index 625e05c1..00a3d886 100644 --- a/buildSrc/src/main/kotlin/java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/java-convention.gradle.kts @@ -52,4 +52,26 @@ tasks.test { tasks.compileJava { options.errorprone.disableWarningsInGeneratedCode.set(true) + // Explicitly states the encoding of the source and test source files, ensuring + // correct execution of the `javac` task. + options.encoding = "UTF-8" + options.compilerArgs.addAll(listOf("-Xlint:unchecked", "-Xlint:deprecation")) + + // Configure Error Prone: + // 1. Exclude generated sources from being analyzed by Error Prone. + // 2. Turn the check off until Error Prone can handle `@Nested` JUnit classes. + // See issue: https://github.com/google/error-prone/issues/956 + // 3. Turn off checks which report unused methods and unused method parameters. + // See issue: https://github.com/SpineEventEngine/config/issues/61 + // + // For more config details see: + // https://github.com/tbroyer/gradle-errorprone-plugin/tree/master#usage + options.errorprone.errorproneArgs.addAll(listOf( + "-XepExcludedPaths:.*/generated/.*", + "-Xep:ClassCanBeStatic:OFF", + "-Xep:UnusedMethod:OFF", + "-Xep:UnusedVariable:OFF", + "-Xep:CheckReturnValue:OFF" + )) + } \ No newline at end of file From 8ad432e9c1f770d02c1d2a553e194a2eadf9402a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:09:39 +0300 Subject: [PATCH 109/492] Fix errorprone issue --- .../main/java/io/spine/chatbot/IncomingEventsController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 7e644c59..1f8f5338 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -36,6 +36,7 @@ import io.spine.json.Json; import io.spine.logging.Logging; +import java.nio.charset.StandardCharsets; import java.util.Base64; /** @@ -85,6 +86,6 @@ private static boolean isThreaded(Space space) { private static String decodeBase64Json(ByteString encoded) { var decodedBytes = Base64.getDecoder() .decode(encoded.toByteArray()); - return new String(decodedBytes); + return new String(decodedBytes, StandardCharsets.UTF_8); } } From d31e383c16e03607e8ac062fb33ec1064822519a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:11:26 +0300 Subject: [PATCH 110/492] Migrate build to kotlin --- .../{build.gradle => build.gradle.kts} | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) rename google-chat-bot/{build.gradle => build.gradle.kts} (65%) diff --git a/google-chat-bot/build.gradle b/google-chat-bot/build.gradle.kts similarity index 65% rename from google-chat-bot/build.gradle rename to google-chat-bot/build.gradle.kts index e0e4faf3..b63fa6db 100644 --- a/google-chat-bot/build.gradle +++ b/google-chat-bot/build.gradle.kts @@ -19,18 +19,16 @@ */ plugins { - id "application" - id "com.github.johnrengelman.shadow" - id "com.google.cloud.tools.jib" - id "io.spine.tools.gradle.bootstrap" + application + id("com.github.johnrengelman.shadow") + id("com.google.cloud.tools.jib") + id("io.spine.tools.gradle.bootstrap") } +val gcpProject: String by project spine { enableJava().server() - modelCompiler { - generateValidation = true - } } dependencies { @@ -51,22 +49,29 @@ dependencies { runtimeOnly("org.apache.logging.log4j:log4j-api:2.13.3") runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.3") - implementation "io.spine.gcloud:spine-datastore:1.5.0" - implementation 'com.google.cloud:google-cloud-secretmanager:1.0.1' - implementation 'com.google.api.grpc:proto-google-cloud-pubsub-v1:1.89.0' + implementation("io.spine.gcloud:spine-datastore:1.5.0") + implementation("com.google.cloud:google-cloud-secretmanager:1.0.1") + implementation("com.google.api.grpc:proto-google-cloud-pubsub-v1:1.89.0") - implementation 'com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9' - implementation 'com.google.auth:google-auth-library-oauth2-http:0.20.0' - testImplementation "io.spine:spine-testutil-server:${spine.version()}" + implementation("com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9") + implementation("com.google.auth:google-auth-library-oauth2-http:0.20.0") + testAnnotationProcessor(enforcedPlatform(Build.micronaut.bom)) + testAnnotationProcessor(Build.micronaut.injectJava) + testImplementation("io.spine:spine-testutil-server:${spine.version()}") + testImplementation(enforcedPlatform(Build.micronaut.bom)) + testImplementation(Build.micronaut.testJUnit5) + testImplementation(Build.micronaut.httpClient) } -mainClassName = "io.spine.chatbot.Application" +application { + mainClassName = "io.spine.chatbot.Application" +} jib { to { image = "gcr.io/${gcpProject}/chat-bot-server" } container { - mainClass = mainClassName + mainClass = application.mainClassName } } From 0591ba8c8354a7c7f270b74cd59bc9dd773810ca Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:23:37 +0300 Subject: [PATCH 111/492] Align dependencies and remove unused --- buildSrc/src/main/kotlin/deps.kt | 50 +++++++++++--------------------- google-chat-bot/build.gradle.kts | 48 +++++++++++++++--------------- 2 files changed, 42 insertions(+), 56 deletions(-) diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index 88429666..f37d6860 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -25,10 +25,8 @@ object Versions { const val checkstyle = "8.29" const val findBugs = "3.0.2" const val guava = "29.0-jre" - const val grpc = "1.28.1" const val flogger = "0.5.1" const val junit5 = "5.6.2" - const val junitPlatform = "1.6.2" const val truth = "1.0.1" const val micronaut = "2.0.0.M3" const val spineGcloud = "1.5.0" @@ -36,24 +34,7 @@ object Versions { const val googlePubsubProto = "1.89.0" const val googleChat = "v1-rev20200502-1.30.9" const val googleAuth = "0.20.0" - - const val licensePlugin = "1.14" - const val errorPronePlugin = "1.2.1" - const val aptPlugin = "0.21" - const val shadowPlugin = "5.2.0" - const val jibPlugin = "2.4.0" - const val spineBootstrapPlugin = "1.5.17" - const val propertiesPlugin = "1.5.1" -} - -object GradlePlugins { - const val apt = "net.ltgt.gradle:gradle-apt-plugin:${Versions.aptPlugin}" - const val shadow = "com.github.jengelman.gradle.plugins:shadow:${Versions.shadowPlugin}" - const val jib = "gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:${Versions.jibPlugin}" - const val properties = "net.saliman:gradle-properties-plugin:${Versions.propertiesPlugin}" - const val spineBootstrap = "io.spine.tools:spine-bootstrap:${Versions.spineBootstrapPlugin}" - const val errorProne = "net.ltgt.gradle:gradle-errorprone-plugin:${Versions.errorPronePlugin}" - const val licenseReport = "com.github.jk1:gradle-license-report:${Versions.licensePlugin}" + const val log4j2 = "2.13.3" } object Build { @@ -73,8 +54,22 @@ object Build { const val guava = "com.google.guava:guava:${Versions.guava}" const val flogger = "com.google.flogger:flogger:${Versions.flogger}" val ci = "true".equals(System.getenv("CI")) - val gradlePlugins = GradlePlugins val micronaut = Micronaut + val google = Google + val log4j2 = Log4j2 +} + +object Log4j2 { + const val core = "org.apache.logging.log4j:log4j-core:${Versions.log4j2}" + const val api = "org.apache.logging.log4j:log4j-api:${Versions.log4j2}" + const val slf4jBridge = "org.apache.logging.log4j:log4j-slf4j-impl:${Versions.log4j2}" +} + +object Google { + const val secretManager = "com.google.cloud:google-cloud-secretmanager:${Versions.googleSecretManager}" + const val pubsubProto = "com.google.api.grpc:proto-google-cloud-pubsub-v1:${Versions.googlePubsubProto}" + const val chat = "com.google.apis:google-api-services-chat:${Versions.googleChat}" + const val auth = "com.google.auth:google-auth-library-oauth2-http:${Versions.googleAuth}" } object Micronaut { @@ -86,17 +81,7 @@ object Micronaut { const val netty = "io.micronaut:micronaut-http-server-netty" const val testJUnit5 = "io.micronaut.test:micronaut-test-junit5" const val httpClient = "io.micronaut:micronaut-http-client" -} - -object Runtime { - - val flogger = Flogger - - object Flogger { - const val systemBackend = "com.google.flogger:flogger-system-backend:${Versions.flogger}" - const val log4J = "com.google.flogger:flogger-log4j:${Versions.flogger}" - const val slf4J = "com.google.flogger:slf4j-backend-factory:${Versions.flogger}" - } + const val annotationApi = "javax.annotation:javax.annotation-api" } object Test { @@ -115,7 +100,6 @@ object Test { object Deps { val build = Build - val runtime = Runtime val test = Test val versions = Versions } diff --git a/google-chat-bot/build.gradle.kts b/google-chat-bot/build.gradle.kts index b63fa6db..e7db3fc8 100644 --- a/google-chat-bot/build.gradle.kts +++ b/google-chat-bot/build.gradle.kts @@ -32,35 +32,37 @@ spine { } dependencies { - annotationProcessor(enforcedPlatform(Build.micronaut.bom)) - annotationProcessor(Build.micronaut.injectJava) - annotationProcessor(Build.micronaut.validation) + annotationProcessor(enforcedPlatform(Deps.build.micronaut.bom)) + annotationProcessor(Deps.build.micronaut.injectJava) + annotationProcessor(Deps.build.micronaut.validation) - compileOnly(enforcedPlatform(Build.micronaut.bom)) + compileOnly(enforcedPlatform(Deps.build.micronaut.bom)) - implementation(enforcedPlatform(Build.micronaut.bom)) - implementation(Build.micronaut.inject) - implementation(Build.micronaut.validation) - implementation(Build.micronaut.runtime) - implementation(Build.micronaut.netty) - implementation("javax.annotation:javax.annotation-api") + implementation(enforcedPlatform(Deps.build.micronaut.bom)) + implementation(Deps.build.micronaut.inject) + implementation(Deps.build.micronaut.validation) + implementation(Deps.build.micronaut.runtime) + implementation(Deps.build.micronaut.netty) + implementation(Deps.build.micronaut.annotationApi) - implementation("org.apache.logging.log4j:log4j-core:2.13.3") - runtimeOnly("org.apache.logging.log4j:log4j-api:2.13.3") - runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.3") + implementation(Deps.build.log4j2.core) + runtimeOnly(Deps.build.log4j2.api) + runtimeOnly(Deps.build.log4j2.slf4jBridge) - implementation("io.spine.gcloud:spine-datastore:1.5.0") - implementation("com.google.cloud:google-cloud-secretmanager:1.0.1") - implementation("com.google.api.grpc:proto-google-cloud-pubsub-v1:1.89.0") + implementation("io.spine.gcloud:spine-datastore:${Deps.versions.spineGcloud}") + implementation(Deps.build.google.secretManager) + implementation(Deps.build.google.pubsubProto) + + implementation(Deps.build.google.chat) + implementation(Deps.build.google.auth) + + testAnnotationProcessor(enforcedPlatform(Deps.build.micronaut.bom)) + testAnnotationProcessor(Deps.build.micronaut.injectJava) - implementation("com.google.apis:google-api-services-chat:v1-rev20200502-1.30.9") - implementation("com.google.auth:google-auth-library-oauth2-http:0.20.0") - testAnnotationProcessor(enforcedPlatform(Build.micronaut.bom)) - testAnnotationProcessor(Build.micronaut.injectJava) testImplementation("io.spine:spine-testutil-server:${spine.version()}") - testImplementation(enforcedPlatform(Build.micronaut.bom)) - testImplementation(Build.micronaut.testJUnit5) - testImplementation(Build.micronaut.httpClient) + testImplementation(enforcedPlatform(Deps.build.micronaut.bom)) + testImplementation(Deps.build.micronaut.testJUnit5) + testImplementation(Deps.build.micronaut.httpClient) } application { From 61d66d3addebc3e24b535ac7f866885f9ad41f9d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:23:48 +0300 Subject: [PATCH 112/492] Cleanup scripts --- build.gradle.kts | 20 ------------------- .../main/kotlin/java-convention.gradle.kts | 1 - version.gradle.kts | 2 +- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index dc2a16c5..33c40115 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,26 +20,6 @@ import net.saliman.gradle.plugin.properties.PropertiesPlugin -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - plugins { idea } diff --git a/buildSrc/src/main/kotlin/java-convention.gradle.kts b/buildSrc/src/main/kotlin/java-convention.gradle.kts index 00a3d886..40969507 100644 --- a/buildSrc/src/main/kotlin/java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/java-convention.gradle.kts @@ -73,5 +73,4 @@ tasks.compileJava { "-Xep:UnusedVariable:OFF", "-Xep:CheckReturnValue:OFF" )) - } \ No newline at end of file diff --git a/version.gradle.kts b/version.gradle.kts index 3d303e84..5073bd1b 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -22,4 +22,4 @@ * The version of the application. */ -val botVersion: String by extra("0.0.1") \ No newline at end of file +val botVersion: String by extra("0.0.1") From d26fbe3732c63f314ea7ec9aeeccd00785814511 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:27:49 +0300 Subject: [PATCH 113/492] Add missing empty line --- buildSrc/src/main/kotlin/java-convention.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/java-convention.gradle.kts b/buildSrc/src/main/kotlin/java-convention.gradle.kts index 40969507..c93a1262 100644 --- a/buildSrc/src/main/kotlin/java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/java-convention.gradle.kts @@ -73,4 +73,4 @@ tasks.compileJava { "-Xep:UnusedVariable:OFF", "-Xep:CheckReturnValue:OFF" )) -} \ No newline at end of file +} From e381fbc38bdf7bc83ffe850b2bf494e77adee0ad Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:28:56 +0300 Subject: [PATCH 114/492] Add missing empty line --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2aef60d1..084555fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,4 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -gcpProject='' \ No newline at end of file +gcpProject='' From ca3eca5ddf600769b93dc2f29b73b4fd86e8ca09 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 15 Jun 2020 17:29:19 +0300 Subject: [PATCH 115/492] Add note about the variable --- google-chat-bot/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/google-chat-bot/build.gradle.kts b/google-chat-bot/build.gradle.kts index e7db3fc8..623da7f7 100644 --- a/google-chat-bot/build.gradle.kts +++ b/google-chat-bot/build.gradle.kts @@ -25,6 +25,7 @@ plugins { id("io.spine.tools.gradle.bootstrap") } +/** The GCP project ID used for deployment of the application. **/ val gcpProject: String by project spine { From f739237c11951cfa5250f19105ee48d49432bb50 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 14:00:29 +0300 Subject: [PATCH 116/492] Add missing docs --- .../java/io/spine/chatbot/Application.java | 1 + .../spine/chatbot/client/ChatBotClient.java | 7 +++- .../io/spine/chatbot/client/package-info.java | 30 +++++++++++++++++ .../spine/chatbot/jackson/package-info.java | 32 +++++++++++++++++++ .../chatbot/server/github/Identifiers.java | 2 +- .../server/github/OrganizationAggregate.java | 3 ++ .../server/google/chat/Identifiers.java | 2 +- 7 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/client/package-info.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 1fc7f89a..ccdddd35 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -37,6 +37,7 @@ public final class Application { private Application() { } + /** Starts the application. **/ public static void main(String[] args) { initializeSpine(); Micronaut.run(Application.class, args); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java index 820fb5b9..861e5cb2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -43,6 +43,11 @@ import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; import static io.spine.net.Urls.urlOfSpec; +/** + * A ChatBot application's Spine client. + * + *

Abstracts working with Spine's {@link Client client}. + */ public final class ChatBotClient { private final Client client; @@ -72,7 +77,7 @@ public boolean cancelSubscription(Subscription subscription) { } /** - * Returns IDs for all registered listRepositories. + * Returns IDs for all registered repositories. */ public ImmutableList listRepositories() { var orgIds = client.asGuest() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/package-info.java new file mode 100644 index 00000000..4915e9fc --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains the ChatBot client. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.client; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java new file mode 100644 index 00000000..025b3c46 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package jackson utilities. + * + * @see jackson + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.jackson; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java index ce86a07e..e8acb082 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java @@ -24,7 +24,7 @@ import io.spine.chatbot.github.RepositoryId; /** - * An utility for working with {@link GitHubContext} identifiers. + * A utility for working with {@link GitHubContext} identifiers. */ public final class Identifiers { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 66500fef..f5116f9b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -28,6 +28,9 @@ import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; +/** + * + */ final class OrganizationAggregate extends Aggregate { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java index 8ff9bac5..94de44ff 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java @@ -27,7 +27,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** - * An utility for working with {@link GoogleChatContext} identifiers. + * A utility for working with {@link GoogleChatContext} identifiers. */ public final class Identifiers { From 846501a64503939730e5775b069a33c485e2631c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 14:06:26 +0300 Subject: [PATCH 117/492] Rename `sendMessage` to `sendBuildStateUpdate` --- .../src/main/java/io/spine/chatbot/api/GoogleChatClient.java | 2 +- .../io/spine/chatbot/server/google/chat/ThreadChatProcess.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 1b4d638a..f04dc4de 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -72,7 +72,7 @@ private GoogleChatClient() { * * @return a sent message */ - public static Message sendMessage(BuildState buildState, @Nullable String threadName) { + public static Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { var message = buildStateMessage(buildState, threadName); return sendMessage(hangoutsChat(), buildState.getGoogleChatSpace(), message); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 27cbb243..489c19df 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -48,7 +48,8 @@ Pair> on(BuildStateChanged e) { var threadId = newThreadId(repositoryId.getValue()); var spaceId = newSpaceId(buildState.getGoogleChatSpace()); var currentThread = state().getThread(); - var sentMessage = GoogleChatClient.sendMessage(buildState, currentThread.getName()); + var sentMessage = GoogleChatClient.sendBuildStateUpdate(buildState, + currentThread.getName()); var thread = sentMessage.getThread(); var messageId = newMessageId(sentMessage.getName()); var messageCreated = MessageCreated From f713154f1446b15c998c3021319820564767ecc9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 14:24:51 +0300 Subject: [PATCH 118/492] Extract dedicated BuildStateUpdates and ChatWidgets helpers --- .../spine/chatbot/api/BuildStateUpdates.java | 106 ++++++++++++++++++ .../io/spine/chatbot/api/ChatWidgets.java | 93 +++++++++++++++ .../spine/chatbot/api/GoogleChatClient.java | 104 +---------------- .../chatbot/api/BuildStateUpdatesTest.java | 32 ++++++ .../io/spine/chatbot/api/ChatWidgetsTest.java | 32 ++++++ 5 files changed, 264 insertions(+), 103 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java new file mode 100644 index 00000000..f7d2aa5b --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java @@ -0,0 +1,106 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.api.services.chat.v1.model.CardHeader; +import com.google.api.services.chat.v1.model.KeyValue; +import com.google.api.services.chat.v1.model.Message; +import com.google.api.services.chat.v1.model.Section; +import com.google.api.services.chat.v1.model.Thread; +import com.google.api.services.chat.v1.model.WidgetMarkup; +import com.google.common.collect.ImmutableList; +import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.validate.Validate; + +import javax.annotation.Nullable; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static io.spine.chatbot.api.ChatWidgets.cardWith; +import static io.spine.chatbot.api.ChatWidgets.linkButton; +import static io.spine.chatbot.api.ChatWidgets.sectionWithWidget; +import static io.spine.chatbot.api.ChatWidgets.textParagraph; + +/** + * A Google Chat utility class that creates {@link BuildState} update messages. + */ +final class BuildStateUpdates { + + /** Prevents instantiation of this utility class. **/ + private BuildStateUpdates() { + } + + /** + * Creates a new {@link BuildState} update message of of the supplied state and the thread name. + * + *

If the thread name is empty, assumes that the update message should be sent + * to a new thread. + */ + static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { + Validate.checkValid(buildState); + var cardHeader = new CardHeader() + .setTitle(buildState.getRepositorySlug()) + .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); + var sections = ImmutableList.of( + buildStateSection(buildState), + commitSection(buildState.getLastCommit()), + actions(buildState) + ); + var message = new Message().setCards(cardWith(cardHeader, sections)); + if (!isNullOrEmpty(threadName)) { + message.setThread(new Thread().setName(threadName)); + } + return message; + } + + private static Section commitSection(BuildState.Commit commit) { + var commitInfo = String.format( + "Authored by %s at %s.", commit.getAuthoredBy(), commit.getCommittedAt() + ); + var section = new Section() + .setHeader("Commit " + commit.getSha()) + .setWidgets(ImmutableList.of( + textParagraph(commit.getMessage()), + textParagraph(commitInfo) + )); + return section; + } + + private static Section actions(BuildState buildState) { + BuildState.Commit commit = buildState.getLastCommit(); + WidgetMarkup actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( + linkButton("Open build", buildState.getTravisCiUrl()), + linkButton("Open changeset", commit.getCompareUrl()) + )); + return sectionWithWidget(actionButtons); + } + + private static Section buildStateSection(BuildState buildState) { + return sectionWithWidget(buildStateWidget(buildState)); + } + + private static WidgetMarkup buildStateWidget(BuildState buildState) { + var keyValue = new KeyValue() + .setTopLabel("Build No.") + .setContent(buildState.getNumber()) + .setBottomLabel(buildState.getState()); + return new WidgetMarkup().setKeyValue(keyValue); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java new file mode 100644 index 00000000..fe3211f7 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java @@ -0,0 +1,93 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.api.services.chat.v1.model.Button; +import com.google.api.services.chat.v1.model.Card; +import com.google.api.services.chat.v1.model.CardHeader; +import com.google.api.services.chat.v1.model.OnClick; +import com.google.api.services.chat.v1.model.OpenLink; +import com.google.api.services.chat.v1.model.Section; +import com.google.api.services.chat.v1.model.TextButton; +import com.google.api.services.chat.v1.model.TextParagraph; +import com.google.api.services.chat.v1.model.WidgetMarkup; +import com.google.common.collect.ImmutableList; +import io.spine.net.Url; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A utility class that provides helper methods for creating Google Chat rich messages. + */ +final class ChatWidgets { + + /** Prevents instantiation of this utility class. **/ + private ChatWidgets() { + } + + /** + * Creates a new button with an on-click open link action with the specified {@code title} + * and {@code url} to open upon a click. + */ + static Button linkButton(String title, Url url) { + checkNotNull(title); + checkNotNull(url); + var button = new TextButton().setText(title) + .setOnClick(openLink(url)); + return new Button().setTextButton(button); + } + + private static OnClick openLink(Url url) { + return new OnClick().setOpenLink(new OpenLink().setUrl(url.getSpec())); + } + + /** + * Creates a singleton cards list with a new {@link Card} with a specified {@code header} + * and {@code sections}. + */ + static ImmutableList cardWith(CardHeader header, List

sections) { + checkNotNull(header); + checkNotNull(sections); + return ImmutableList.of(new Card().setHeader(header) + .setSections(sections)); + } + + /** + * Creates a new {@link Section} with a single {@code widget}. + */ + static Section sectionWithWidget(WidgetMarkup widget) { + checkNotNull(widget); + return new Section().setWidgets(List.of(widget)); + } + + /** + * Creates a new {@link TextParagraph} widget with the supplied {@code formattedText}. + * + * @see + * Card text formatting + */ + static WidgetMarkup textParagraph(String formattedText) { + checkNotNull(formattedText); + return new WidgetMarkup().setTextParagraph(new TextParagraph().setText(formattedText)); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index f04dc4de..9f6f17ae 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -23,33 +23,17 @@ import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.chat.v1.HangoutsChat; -import com.google.api.services.chat.v1.model.Button; -import com.google.api.services.chat.v1.model.Card; -import com.google.api.services.chat.v1.model.CardHeader; -import com.google.api.services.chat.v1.model.KeyValue; import com.google.api.services.chat.v1.model.Message; -import com.google.api.services.chat.v1.model.OnClick; -import com.google.api.services.chat.v1.model.OpenLink; -import com.google.api.services.chat.v1.model.Section; -import com.google.api.services.chat.v1.model.Space; -import com.google.api.services.chat.v1.model.TextButton; -import com.google.api.services.chat.v1.model.TextParagraph; -import com.google.api.services.chat.v1.model.Thread; -import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; -import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.build.BuildState; -import io.spine.net.Url; -import io.spine.validate.Validate; import javax.annotation.Nullable; import java.io.IOException; import java.security.GeneralSecurityException; -import java.util.List; -import static com.google.common.base.Strings.isNullOrEmpty; +import static io.spine.chatbot.api.BuildStateUpdates.buildStateMessage; /** * Google Chat client. @@ -94,18 +78,6 @@ private static HangoutsChat hangoutsChat() { } } - private static List listSpaces(HangoutsChat chat) { - try { - return chat - .spaces() - .list() - .execute() - .getSpaces(); - } catch (IOException e) { - throw new RuntimeException("Unable to retrieve available spaces.", e); - } - } - @CanIgnoreReturnValue private static Message sendMessage(HangoutsChat chat, String space, Message message) { try { @@ -118,78 +90,4 @@ private static Message sendMessage(HangoutsChat chat, String space, Message mess throw new RuntimeException("Unable to send message to space " + space, e); } } - - private static ImmutableList cardWith(CardHeader header, List
sections) { - return ImmutableList.of(new Card().setHeader(header) - .setSections(sections)); - } - - private static Section sectionWithWidget(WidgetMarkup widget) { - return new Section().setWidgets(List.of(widget)); - } - - private static Section commitSection(BuildState.Commit commit) { - var commitInfo = String.format( - "Authored by %s at %s.", commit.getAuthoredBy(), commit.getCommittedAt() - ); - var section = new Section() - .setHeader("Commit " + commit.getSha()) - .setWidgets(ImmutableList.of( - textParagraph(commit.getMessage()), - textParagraph(commitInfo) - )); - return section; - } - - private static Section actions(BuildState buildState) { - BuildState.Commit commit = buildState.getLastCommit(); - WidgetMarkup actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( - linkButton("Open build", buildState.getTravisCiUrl()), - linkButton("Open changeset", commit.getCompareUrl()) - )); - return sectionWithWidget(actionButtons); - } - - private static WidgetMarkup textParagraph(String formattedText) { - return new WidgetMarkup().setTextParagraph(new TextParagraph().setText(formattedText)); - } - - private static Section buildStateSection(BuildState buildState) { - return sectionWithWidget(buildStateWidget(buildState)); - } - - private static WidgetMarkup buildStateWidget(BuildState buildState) { - var keyValue = new KeyValue() - .setTopLabel("Build No.") - .setContent(buildState.getNumber()) - .setBottomLabel(buildState.getState()); - return new WidgetMarkup().setKeyValue(keyValue); - } - - private static Button linkButton(String title, Url url) { - var button = new TextButton().setText(title) - .setOnClick(openLink(url)); - return new Button().setTextButton(button); - } - - private static OnClick openLink(Url url) { - return new OnClick().setOpenLink(new OpenLink().setUrl(url.getSpec())); - } - - private static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { - Validate.checkValid(buildState); - var cardHeader = new CardHeader() - .setTitle(buildState.getRepositorySlug()) - .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); - var sections = ImmutableList.of( - buildStateSection(buildState), - commitSection(buildState.getLastCommit()), - actions(buildState) - ); - var message = new Message().setCards(cardWith(cardHeader, sections)); - if (!isNullOrEmpty(threadName)) { - message.setThread(new Thread().setName(threadName)); - } - return message; - } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java new file mode 100644 index 00000000..c9b127f7 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("BuildStateUpdates should") +final class BuildStateUpdatesTest extends UtilityClassTest { + + BuildStateUpdatesTest() { + super(BuildStateUpdates.class); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java new file mode 100644 index 00000000..079aa201 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("ChatWidgets should") +final class ChatWidgetsTest extends UtilityClassTest { + + ChatWidgetsTest() { + super(ChatWidgets.class); + } +} From a413ce621c8c959bc3265af1d743650a55e2c1ed Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 14:37:11 +0300 Subject: [PATCH 119/492] Extract default initialization from the chatbot client --- .../java/io/spine/chatbot/InitController.java | 47 ++++++++++++++++++- .../spine/chatbot/client/ChatBotClient.java | 34 -------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index 0d7d52e0..938fe2d6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -22,20 +22,63 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.QueryValue; import io.spine.chatbot.client.ChatBotClient; +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.github.repository.event.RepositoryRegistered; import io.spine.logging.Logging; +import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; +import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; +import static io.spine.net.Urls.urlOfSpec; + /** * A REST controller for handling initialization of the application state. */ @Controller("/init") public class InitController implements Logging { + /** + * Performs the initial registration of the default Spine resources the bot is going + * to watch for for a particular Google Chat space. + */ @Get - public String initState() { + public String initWatchedResources(@QueryValue String spaceName) { _info().log("Performing initial application state initialization."); var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); - client.initializeDefaults(); + var spineOrgId = newOrganizationId("SpineEventEngine"); + registerOrganization(client, spineOrgId, spaceName); + registerBase(client, spineOrgId); return "Successfully initialized"; } + + private static void registerBase(ChatBotClient client, OrganizationId spineOrgId) { + var registerSpineBase = RegisterRepository + .newBuilder() + .setOrganization(spineOrgId) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) + .setId(newRepositoryId("SpineEventEngine/base")) + .setName("Spine Event Engine Base") + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) + .vBuild(); + client.postSyncCommand(registerSpineBase, RepositoryRegistered.class); + } + + private static void registerOrganization(ChatBotClient client, + OrganizationId spineOrgId, + String spaceName) { + var registerSpineOrg = RegisterOrganization + .newBuilder() + .setName("Spine Event Engine") + .setWebsiteUrl(urlOfSpec("https://spine.io/")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine")) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine")) + .setId(spineOrgId) + .setGoogleChatSpace(spaceName) + .vBuild(); + client.postSyncCommand(registerSpineOrg, OrganizationRegistered.class); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java index 861e5cb2..21c32129 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -27,10 +27,6 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; -import io.spine.chatbot.github.organization.command.RegisterOrganization; -import io.spine.chatbot.github.organization.event.OrganizationRegistered; -import io.spine.chatbot.github.repository.command.RegisterRepository; -import io.spine.chatbot.github.repository.event.RepositoryRegistered; import io.spine.client.Client; import io.spine.client.ClientRequest; import io.spine.client.Subscription; @@ -39,9 +35,6 @@ import java.util.concurrent.CountDownLatch; import static com.google.common.collect.ImmutableList.toImmutableList; -import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; -import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; -import static io.spine.net.Urls.urlOfSpec; /** * A ChatBot application's Spine client. @@ -97,33 +90,6 @@ public ImmutableList listRepositories() { return result; } - /** - * Performs initialization of the entities that are monitored by the ChatBot - * by default. - */ - public void initializeDefaults() { - var spineOrgId = newOrganizationId("SpineEventEngine"); - var registerSpineOrg = RegisterOrganization - .newBuilder() - .setName("Spine Event Engine") - .setWebsiteUrl(urlOfSpec("https://spine.io/")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine")) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine")) - .setId(spineOrgId) - .setGoogleChatSpace("spaces/AAAAnLxnh_o") - .vBuild(); - postSyncCommand(registerSpineOrg, OrganizationRegistered.class); - var registerSpineBase = RegisterRepository - .newBuilder() - .setOrganization(spineOrgId) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) - .setId(newRepositoryId("SpineEventEngine/base")) - .setName("Spine Event Engine Base") - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) - .vBuild(); - postSyncCommand(registerSpineBase, RepositoryRegistered.class); - } - /** * Posts a command and waits synchronously till the expected outcome event is published. */ From 36d507ce37cb06c89fdbd4ea3b2f212dfa94d797 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 15:15:17 +0300 Subject: [PATCH 120/492] Use the new `@External` annotation --- .../spine/chatbot/server/google/chat/ThreadChatProcess.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 489c19df..0b3b4841 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -27,6 +27,7 @@ import io.spine.chatbot.google.chat.event.MessageCreated; import io.spine.chatbot.google.chat.event.ThreadCreated; import io.spine.chatbot.google.chat.thread.ThreadChat; +import io.spine.core.External; import io.spine.server.event.React; import io.spine.server.procman.ProcessManager; import io.spine.server.tuple.Pair; @@ -40,8 +41,8 @@ final class ThreadChatProcess extends ProcessManager { - @React(external = true) - Pair> on(BuildStateChanged e) { + @React + Pair> on(@External BuildStateChanged e) { var change = e.getChange(); var buildState = change.getNewValue(); var repositoryId = e.getId(); From 76ff1940d3dda91f3cec3e0e39086498329ce187 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 15:23:32 +0300 Subject: [PATCH 121/492] remove empty comment --- .../io/spine/chatbot/server/github/OrganizationAggregate.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index f5116f9b..66500fef 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -28,9 +28,6 @@ import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; -/** - * - */ final class OrganizationAggregate extends Aggregate { From 97e191eab6bf00f4f625e68691c40b9a9eac8138 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 15:24:04 +0300 Subject: [PATCH 122/492] update IDEA configs --- .idea/misc.xml | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index ae47d10d..6460a4d8 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,12 +1,24 @@ + + + + + + + + + + + - + \ No newline at end of file From 7f08a1a960b9085fbbbc15d49e7a7e575a91f253 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 15:24:33 +0300 Subject: [PATCH 123/492] Add IDEA http client configs --- .gitignore | 3 +++ http-client.env.json | 6 ++++++ travis-ci.http | 13 ++++++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 http-client.env.json diff --git a/.gitignore b/.gitignore index 7a0aa46d..3d2fa229 100644 --- a/.gitignore +++ b/.gitignore @@ -246,3 +246,6 @@ gradle-local.properties # Local credentials folder .credentials + +# IDEA HTTP client private env files +http-client.private.env.json \ No newline at end of file diff --git a/http-client.env.json b/http-client.env.json new file mode 100644 index 00000000..6dae7db5 --- /dev/null +++ b/http-client.env.json @@ -0,0 +1,6 @@ +{ + "travis": { + "host": "api.travis-ci.com", + "token": "" + } +} \ No newline at end of file diff --git a/travis-ci.http b/travis-ci.http index 3932db46..3ccd26bf 100644 --- a/travis-ci.http +++ b/travis-ci.http @@ -1,6 +1,13 @@ -### +### List Travis CI builds for a repository -GET https://api.travis-ci.com/repo/SpineEventEngine%2Fbase/builds?limit=1&branch.name=master +GET https://{{host}}/repo/SpineEventEngine%2Fbase/builds?limit=1&branch.name=master&include=build.commit Accept: application/json -Authorization: token +Authorization: token {{token}} +Travis-API-Version: 3 + +### List Travis CI repositories for a user + +GET https://{{host}}/owner/SpineEventEngine/repos +Accept: application/json +Authorization: token {{token}} Travis-API-Version: 3 From 608aaed428f9a8e9f00e6093365627d28d2329fd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 15:26:45 +0300 Subject: [PATCH 124/492] Add new annotation that is treated as the entry point --- .idea/misc.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 6460a4d8..868b4d01 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,10 +1,11 @@ - - - - + + + + + From e0699f904dbe1ba7f81fc78d230bcdfcd9746e3a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 15:26:59 +0300 Subject: [PATCH 125/492] Add Repositories API response wrapper --- .../src/main/proto/spine/chatbot/travis/travis.proto | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index c7a097b4..3f08ae0a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -134,3 +134,9 @@ message BuildsResponse { repeated Build builds = 1; } + +// A travis `repos` API endpoint response. +message RepositoriesResponse { + + repeated Repository repositories = 1; +} \ No newline at end of file From 8eb8c9eef50056c7c856d94f880ce29d7419be76 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 16:41:19 +0300 Subject: [PATCH 126/492] Add API to query repositories --- .../io/spine/chatbot/api/TravisClient.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index c310a182..b193df94 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -20,7 +20,9 @@ package io.spine.chatbot.api; +import com.google.protobuf.Message; import io.spine.chatbot.travis.BuildsResponse; +import io.spine.chatbot.travis.RepositoriesResponse; import java.io.IOException; import java.net.URI; @@ -30,6 +32,7 @@ import java.nio.charset.StandardCharsets; import static io.spine.chatbot.api.JsonProtoBodyHandler.jsonBodyHandler; +import static java.lang.String.format; /** * A Travis CI API client. @@ -65,15 +68,32 @@ public static TravisClient defaultTravisClient() { */ public BuildsResponse queryBuildsFor(String repoSlug) { var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); - var repoBuilds = "/repo/" + var repositoryBuildsQuery = "/repo/" + encodedSlug + "/builds?limit=1&branch.name=master&include=build.commit"; - var request = apiRequest(repoBuilds, apiToken); + var result = queryForResponse(repositoryBuildsQuery, BuildsResponse.class); + return result; + } + + /** + * Queries Travis CI repositories information for a specified {@code owner}. + */ + public RepositoriesResponse queryRepositoriesFor(String owner) { + var encodedOwner = URLEncoder.encode(owner, StandardCharsets.UTF_8); + var ownerRepositoriesQuery = "/owner/" + encodedOwner + "/repos"; + var result = queryForResponse(ownerRepositoriesQuery, RepositoriesResponse.class); + return result; + } + + private T queryForResponse(String query, Class responseType) { + var request = apiRequest(query, apiToken); try { - var result = CLIENT.send(request, jsonBodyHandler(BuildsResponse.class)); + var result = CLIENT.send(request, jsonBodyHandler(responseType)); return result.body(); } catch (IOException | InterruptedException e) { - throw new RuntimeException("Unable to retrieve repository " + repoSlug + " builds.", e); + var message = format("Unable to query data for response of type '%s' using query '%s'.", + responseType, query); + throw new RuntimeException(message, e); } } From 8661702e6cbb02ea4625d41986a3d6a1fe468929 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 18:08:36 +0300 Subject: [PATCH 127/492] Add shortcuts for build URLs --- .../server/github/RepositoryBuildProcess.java | 9 +---- .../src/main/java/io/spine/net/Urls.java | 29 ++++++++++++++ .../src/test/java/io/spine/net/UrlsTest.java | 39 +++++++++++++++++++ 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index ca5b6c4a..f7e0814b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -29,12 +29,12 @@ import io.spine.chatbot.github.repository.build.event.BuildStateChanged; import io.spine.chatbot.travis.Build; import io.spine.chatbot.travis.Commit; -import io.spine.net.Url; import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; import static io.spine.chatbot.api.TravisClient.defaultTravisClient; +import static io.spine.net.Urls.travisBuildUrlFor; final class RepositoryBuildProcess extends ProcessManager { @@ -76,15 +76,10 @@ private static BuildState from(Build build) { .setCreatedBy(build.getCreatedBy() .getLogin()) .setRepositorySlug(slug) - .setTravisCiUrl(newTravisCiUrlFor(slug, build.getId())) + .setTravisCiUrl(travisBuildUrlFor(slug, build.getId())) .vBuild(); } - private static Url newTravisCiUrlFor(String repoSlug, long buildId) { - var spec = String.format("https://travis-ci.com/github/%s/builds/%d", repoSlug, buildId); - return Urls.urlOfSpec(spec); - } - private static BuildState.Commit from(Commit commit) { return BuildState.Commit .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/net/Urls.java b/google-chat-bot/src/main/java/io/spine/net/Urls.java index 4d7c2cc3..480de6b7 100644 --- a/google-chat-bot/src/main/java/io/spine/net/Urls.java +++ b/google-chat-bot/src/main/java/io/spine/net/Urls.java @@ -20,11 +20,17 @@ package io.spine.net; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.String.format; + /** * An utility for working with {@link Url}. */ public final class Urls { + private static final String TRAVIS_GITHUB_ENDPOINT = "https://travis-ci.com/github"; + private static final String GITHUB = "https://github.com"; + /** * Prevents instantiation of this utility class. */ @@ -37,4 +43,27 @@ public static Url urlOfSpec(String spec) { .setSpec(spec) .vBuild(); } + + /** Creates a new Travis CI build URL. **/ + public static Url travisBuildUrlFor(String repoSlug, long buildId) { + checkNotNull(repoSlug); + var spec = format("%s/%s/builds/%d", + TRAVIS_GITHUB_ENDPOINT, repoSlug, buildId); + return urlOfSpec(spec); + } + + /** Creates a new Travis CI repository URL. **/ + public static Url travisRepoUrlFor(String repoSlug) { + checkNotNull(repoSlug); + var spec = format("%s/%s", + TRAVIS_GITHUB_ENDPOINT, repoSlug); + return urlOfSpec(spec); + } + + /** Creates a new GitHub repository URL. **/ + public static Url githubRepoUrlFor(String repoSlug) { + checkNotNull(repoSlug); + var spec = format("%s/%s", GITHUB, repoSlug); + return urlOfSpec(spec); + } } diff --git a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java index 1974b015..d784e7ed 100644 --- a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java @@ -22,11 +22,50 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import static io.spine.net.Urls.githubRepoUrlFor; +import static io.spine.net.Urls.travisBuildUrlFor; +import static io.spine.net.Urls.travisRepoUrlFor; +import static io.spine.net.Urls.urlOfSpec; @DisplayName("Urls should") final class UrlsTest extends UtilityClassTest { + private static final String REPO_SLUG = "SpineEventEngine/chat-bot"; + UrlsTest() { super(Urls.class); } + + @DisplayName("compose URL for") + @Nested + final class Compose { + + @DisplayName("Travis CI repository page") + @Test + void travisRepo() { + assertThat(travisRepoUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( + "https://travis-ci.com/github/SpineEventEngine/chat-bot" + )); + } + + @DisplayName("Travis CI repository build page") + @Test + void travisBuild() { + assertThat(travisBuildUrlFor(REPO_SLUG, 331)).isEqualTo(urlOfSpec( + "https://travis-ci.com/github/SpineEventEngine/chat-bot/builds/331" + )); + } + + @DisplayName("GitHub repository page") + @Test + void githubRepo() { + assertThat(githubRepoUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( + "https://github.com/SpineEventEngine/chat-bot" + )); + } + } } From bb7d6b38cfdb778b6adfc2472b85e9c113975b01 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 18:10:13 +0300 Subject: [PATCH 128/492] Do register all watched repos during the initialization --- .../java/io/spine/chatbot/InitController.java | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index 938fe2d6..1d498f7a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -20,6 +20,7 @@ package io.spine.chatbot; +import com.google.common.collect.ImmutableList; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; @@ -29,10 +30,14 @@ import io.spine.chatbot.github.organization.event.OrganizationRegistered; import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.github.repository.event.RepositoryRegistered; +import io.spine.chatbot.travis.Repository; import io.spine.logging.Logging; +import static io.spine.chatbot.api.TravisClient.defaultTravisClient; import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; +import static io.spine.net.Urls.githubRepoUrlFor; +import static io.spine.net.Urls.travisRepoUrlFor; import static io.spine.net.Urls.urlOfSpec; /** @@ -41,6 +46,10 @@ @Controller("/init") public class InitController implements Logging { + private static final ImmutableList WATCHED_REPOS = ImmutableList.of( + "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" + ); + /** * Performs the initial registration of the default Spine resources the bot is going * to watch for for a particular Google Chat space. @@ -51,20 +60,33 @@ public String initWatchedResources(@QueryValue String spaceName) { var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); var spineOrgId = newOrganizationId("SpineEventEngine"); registerOrganization(client, spineOrgId, spaceName); - registerBase(client, spineOrgId); + registerWatchedRepos(client, spineOrgId); return "Successfully initialized"; } - private static void registerBase(ChatBotClient client, OrganizationId spineOrgId) { - var registerSpineBase = RegisterRepository + private static void registerWatchedRepos(ChatBotClient client, OrganizationId spineOrgId) { + defaultTravisClient() + .queryRepositoriesFor(spineOrgId.getValue()) + .getRepositoriesList() + .stream() + .filter(repository -> WATCHED_REPOS.contains(repository.getName())) + .map(repository -> newRegisterRepoCommand(repository, spineOrgId)) + .forEach(registerRepository -> { + client.postSyncCommand(registerRepository, RepositoryRegistered.class); + }); + } + + private static RegisterRepository newRegisterRepoCommand(Repository repository, + OrganizationId orgId) { + var slug = repository.getSlug(); + return RegisterRepository .newBuilder() - .setOrganization(spineOrgId) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine/base")) - .setId(newRepositoryId("SpineEventEngine/base")) - .setName("Spine Event Engine Base") - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base")) + .setOrganization(orgId) + .setGithubUrl(githubRepoUrlFor(slug)) + .setId(newRepositoryId(slug)) + .setName(repository.getName()) + .setTravisCiUrl(travisRepoUrlFor(slug)) .vBuild(); - client.postSyncCommand(registerSpineBase, RepositoryRegistered.class); } private static void registerOrganization(ChatBotClient client, From 861788fc86863a3e447109c12dd8a91078d5660d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 22:58:45 +0300 Subject: [PATCH 129/492] Add `+x` chmod --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From fb43c5734bf0427e13b599e398f3ab6b853894a7 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 22:58:57 +0300 Subject: [PATCH 130/492] bump dependencies --- buildSrc/src/main/kotlin/deps.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index f37d6860..913306c5 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -19,16 +19,16 @@ */ object Versions { - const val checkerFramework = "3.3.0" + const val checkerFramework = "3.4.1" const val errorProne = "2.4.0" - const val pmd = "6.20.0" + const val pmd = "6.24.0" const val checkstyle = "8.29" const val findBugs = "3.0.2" const val guava = "29.0-jre" const val flogger = "0.5.1" const val junit5 = "5.6.2" const val truth = "1.0.1" - const val micronaut = "2.0.0.M3" + const val micronaut = "2.0.0.RC1" const val spineGcloud = "1.5.0" const val googleSecretManager = "1.0.1" const val googlePubsubProto = "1.89.0" From e45b2789ff06afa4433f29f0f82b788d65c68738 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:10:26 +0300 Subject: [PATCH 131/492] Add cloudbuild configuration --- cloudbuild.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 cloudbuild.yaml diff --git a/cloudbuild.yaml b/cloudbuild.yaml new file mode 100644 index 00000000..2c1cfc15 --- /dev/null +++ b/cloudbuild.yaml @@ -0,0 +1,20 @@ +steps: + - name: 'gradle:6.4.1-jdk11' + entrypoint: 'gradle' + args: [ 'build', 'jib', '-PgcpProject=${PROJECT_ID}' ] + - name: 'google/cloud-sdk:slim' + entrypoint: 'gcloud' + args: [ + 'run', 'deploy', '${_SERVICE_NAME}', + '--image', 'gcr.io/${PROJECT_ID}/${_SERVICE_NAME}', + '--region', 'europe-west1', + '--platform', 'managed', + '--project', '${PROJECT_ID}' + ] +timeout: 1200s +substitutions: + _SERVICE_NAME: "chat-bot-server" + +images: [ + 'gcr.io/${PROJECT_ID}/${_SERVICE_NAME}:latest' +] From 5b8ce312dd8c60c19a7b0bf93ba0c3232c5e132b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:10:56 +0300 Subject: [PATCH 132/492] Add TODO about resolving the cloud build issue with missing Generated annotation --- cloudbuild.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 2c1cfc15..82fae511 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,3 +1,6 @@ +# TODO:2020-06-17:yuri-sergiichuk: the build fails in the cloud with +# java.lang.NoClassDefFoundError: javax/annotation/Generated inside Spine protoc plugin + steps: - name: 'gradle:6.4.1-jdk11' entrypoint: 'gradle' From 3106afe67630bb4d19bf74ffb154bfa1a766c0e3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:12:10 +0300 Subject: [PATCH 133/492] Add missing EOF --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3d2fa229..1670b25a 100644 --- a/.gitignore +++ b/.gitignore @@ -248,4 +248,4 @@ gradle-local.properties .credentials # IDEA HTTP client private env files -http-client.private.env.json \ No newline at end of file +http-client.private.env.json From 03f3799e523f9b4d42aebd6d139a0dd5e8359d10 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:13:27 +0300 Subject: [PATCH 134/492] Drop tar/zip dists part --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index bd5995c3..09bbcead 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,12 @@ via the [Google Chat][google-chat]. ## Build -In order to build a distributive of the application, run: +In order to build the application, run: ```bash ./gradlew clean build ``` -The `.tar` and `.zip` dists should be available under `build/distributions`. - Also, it is possible to build a Docker image using [`jib`][jib]: ```bash From 33f2ef2c56e523dc62beeee1e8ac5c40c7ff327a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:14:39 +0300 Subject: [PATCH 135/492] Fix misprint --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09bbcead..354036cc 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ docker run \ ``` The application will be available at `127.0.0.1:${LOCAL_PORT}` (e.g. `127.0.0.1:9090`). -Locally-supplied GCP credentials are mount into the image directly. +Locally-supplied GCP credentials are mounted into the image directly. For detailed ADC credentials guide for Docker see example Cloud Run [guide][cloud-run-local-guide]. From bf474703a275b9cc2ec472ddc18294a3d25d85e3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:15:49 +0300 Subject: [PATCH 136/492] Add ADC in full form --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 354036cc..2e848aad 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ docker run \ The application will be available at `127.0.0.1:${LOCAL_PORT}` (e.g. `127.0.0.1:9090`). Locally-supplied GCP credentials are mounted into the image directly. -For detailed ADC credentials guide for Docker see example Cloud Run [guide][cloud-run-local-guide]. +For detailed Application Default Credentials (ADC) guide for Docker see example +Cloud Run [guide][cloud-run-local-guide]. [cloud-run-local-guide]: https://cloud.google.com/run/docs/testing/local#running_locally_using_docker_with_access_to_services From 63cbbfae9d5d4fcf44af4326a0605de187a40963 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:32:04 +0300 Subject: [PATCH 137/492] Cleanup code and docs. --- .../spine/chatbot/IncomingEventsController.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 1f8f5338..4ce3e12d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -22,7 +22,6 @@ import com.google.protobuf.ByteString; import com.google.pubsub.v1.PubsubPushNotification; -import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; @@ -39,15 +38,21 @@ import java.nio.charset.StandardCharsets; import java.util.Base64; +import static io.micronaut.http.MediaType.APPLICATION_JSON; + /** - * A REST controller for handling incoming PubSub events from Google Chat users. + * A REST controller for handling incoming events from Google Chat. */ @Controller("/chat") public class IncomingEventsController implements Logging { - /** Requests build status checks for registered listRepositories. **/ - @Post(value = "/incoming/event", consumes = MediaType.APPLICATION_JSON) - public String checkRepositoryStatuses(@Body PubsubPushNotification pushNotification) { + /** + * Processes an incoming Google Chat event. + * + *

When a bot is added to a new space, registers the space in the system. + */ + @Post(value = "/incoming/event", consumes = APPLICATION_JSON) + public String on(@Body PubsubPushNotification pushNotification) { var message = pushNotification.getMessage(); var chatEventJson = decodeBase64Json(message.getData()); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); From 9e063913d794a50ce7a62c9bc54bdfcf4ee45a10 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:36:26 +0300 Subject: [PATCH 138/492] Do not use Stream API for business logic --- .../java/io/spine/chatbot/InitController.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index 1d498f7a..6cd0716a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -56,7 +56,9 @@ public class InitController implements Logging { */ @Get public String initWatchedResources(@QueryValue String spaceName) { - _info().log("Performing initial application state initialization."); + _info().log( + "Performing initial application state initialization in the Google Chat space `%s`", + spaceName); var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); var spineOrgId = newOrganizationId("SpineEventEngine"); registerOrganization(client, spineOrgId, spaceName); @@ -65,19 +67,19 @@ public String initWatchedResources(@QueryValue String spaceName) { } private static void registerWatchedRepos(ChatBotClient client, OrganizationId spineOrgId) { - defaultTravisClient() + var watchedRepositories = defaultTravisClient() .queryRepositoriesFor(spineOrgId.getValue()) .getRepositoriesList() .stream() - .filter(repository -> WATCHED_REPOS.contains(repository.getName())) - .map(repository -> newRegisterRepoCommand(repository, spineOrgId)) - .forEach(registerRepository -> { - client.postSyncCommand(registerRepository, RepositoryRegistered.class); - }); + .filter(repository -> WATCHED_REPOS.contains(repository.getName())); + watchedRepositories.forEach(repository -> { + var registerRepository = registerRepoCommand(repository, spineOrgId); + client.postSyncCommand(registerRepository, RepositoryRegistered.class); + }); } - private static RegisterRepository newRegisterRepoCommand(Repository repository, - OrganizationId orgId) { + private static RegisterRepository registerRepoCommand(Repository repository, + OrganizationId orgId) { var slug = repository.getSlug(); return RegisterRepository .newBuilder() From 5af43dd662d72bb779054f7a4175bdefe828f731 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:36:45 +0300 Subject: [PATCH 139/492] improve wording --- .../java/io/spine/chatbot/BeanFactory.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index c1b86e2c..91e54de7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot; import io.micronaut.context.annotation.Bean; @@ -12,7 +32,10 @@ @Factory public class BeanFactory { - /** Registers Pubsub push notification Jackson deserializer. **/ + /** + * Registers {@link com.google.pubsub.v1.PubsubPushNotification push notification} + * Jackson deserializer. + */ @Singleton @Bean public PubsubPushNotificationDeserializer pubsubDeserializer() { From c1a67204ddf28cbe9dadee90c6d8e42a2825bec3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:38:01 +0300 Subject: [PATCH 140/492] Stop using `new` in method names --- .../chatbot/ChatBotServerEnvironment.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index dd2d1456..c6377cf5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -31,7 +31,17 @@ import io.spine.server.storage.memory.InMemoryStorageFactory; import io.spine.server.transport.memory.InMemoryTransportFactory; -/** ChatBot server environment definition. **/ +/** + * ChatBot server environment definition. + * + *

Initializes the {@link ServerEnvironment}. + * + *

Configures the {@link StorageFactory} based on + * the current {@link Environment} — Datastore-based for Production and in-memory-based for tests. + * + *

Configures the inbox delivery through the Datastore work registry while + * in Production environment, otherwise uses local synchronous delivery. + */ final class ChatBotServerEnvironment { private static final int NUMBER_OF_SHARDS = 50; @@ -46,13 +56,13 @@ private ChatBotServerEnvironment() { static void initializeEnvironment() { var se = ServerEnvironment.instance(); var environment = Environment.instance(); - StorageFactory storageFactory = newStorageFactory(environment); + StorageFactory storageFactory = storageFactoryFor(environment); se.configureStorage(storageFactory); se.configureTransport(InMemoryTransportFactory.newInstance()); - se.configureDelivery(newDelivery(environment, storageFactory)); + se.configureDelivery(deliveryFor(environment, storageFactory)); } - private static Delivery newDelivery(Environment environment, StorageFactory storageFactory) { + private static Delivery deliveryFor(Environment environment, StorageFactory storageFactory) { if (environment.isProduction()) { var dsStorageFactory = (DatastoreStorageFactory) storageFactory; var workRegistry = new DsShardedWorkRegistry(dsStorageFactory); @@ -68,7 +78,7 @@ private static Delivery newDelivery(Environment environment, StorageFactory stor return Delivery.local(); } - private static StorageFactory newStorageFactory(Environment environment) { + private static StorageFactory storageFactoryFor(Environment environment) { if (environment.isProduction()) { var datastore = DatastoreOptions.getDefaultInstance() .getService(); From 3a9ad92485d566acba0da92c74cb5b3c2096f7a0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:38:24 +0300 Subject: [PATCH 141/492] mention the `null` behavior --- .../main/java/io/spine/chatbot/api/BuildStateUpdates.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java index f7d2aa5b..13b2fcc5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java @@ -48,10 +48,11 @@ private BuildStateUpdates() { } /** - * Creates a new {@link BuildState} update message of of the supplied state and the thread name. + * Creates a new {@link BuildState} update message of of the supplied state and the thread + * name. * - *

If the thread name is empty, assumes that the update message should be sent - * to a new thread. + *

If the thread name is {@code null} or empty, assumes that the update message should be + * sent to a new thread. */ static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { Validate.checkValid(buildState); From 589bcfdee024038c542290d8110eb248c2d90cf2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:49:05 +0300 Subject: [PATCH 142/492] Rename controller and drop usage of stream API --- ...oller.java => RepositoriesController.java} | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{CronController.java => RepositoriesController.java} (67%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java similarity index 67% rename from google-chat-bot/src/main/java/io/spine/chatbot/CronController.java rename to google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 14e57d09..79526b7e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/CronController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -20,45 +20,49 @@ package io.spine.chatbot; -import com.google.common.collect.ImmutableSet; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; import io.spine.chatbot.client.ChatBotClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; -import io.spine.client.CommandRequest; import static io.spine.chatbot.Application.SERVER_NAME; import static io.spine.util.Exceptions.newIllegalStateException; /** - * A REST controller for handling CRON-based requests from GCP. + * A REST controller handling Repository commands. */ -@Controller("/cron") -public class CronController { +@Controller("/repositories") +public class RepositoriesController { - /** Requests build status checks for registered listRepositories. **/ - @Post("/repositories/check") - public String checkRepositoryStatuses() { + /** + * Sends {@link CheckRepositoryBuild} commands to all repositories registered in the system. + */ + @Post("/check") + public String checkBuildStatuses() { var botClient = ChatBotClient.inProcessClient(SERVER_NAME); botClient.listRepositories() - .stream() - .map(CronController::newCheckRepoBuildCommand) - .map(botClient.asGuest()::command) - .map(request -> request.onStreamingError(CronController::throwProcessingError)) - .map(CommandRequest::post) - .flatMap(ImmutableSet::stream) - .forEach(botClient::cancelSubscription); + .forEach(repository -> checkBuildStatus(botClient, repository)); return "success"; } + private static void checkBuildStatus(ChatBotClient botClient, RepositoryId repository) { + var checkRepositoryBuild = checkRepoBuildCommand(repository); + var subscriptions = botClient + .asGuest() + .command(checkRepositoryBuild) + .onStreamingError(RepositoriesController::throwProcessingError) + .post(); + subscriptions.forEach(botClient::cancelSubscription); + } + private static void throwProcessingError(Throwable throwable) { throw newIllegalStateException( - throwable, "An error while processing the command result." + throwable, "An error while processing the command." ); } - private static CheckRepositoryBuild newCheckRepoBuildCommand(RepositoryId id) { + private static CheckRepositoryBuild checkRepoBuildCommand(RepositoryId id) { return CheckRepositoryBuild .newBuilder() .setId(id) From 0231c96cf9229ff1859ea632cc34e99cf8ea1490 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:49:35 +0300 Subject: [PATCH 143/492] Add docs about exposed REST APIs --- .../main/java/io/spine/chatbot/Application.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index ccdddd35..2b4ddacf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -28,7 +28,22 @@ import java.io.IOException; -/** The entry point to the Google Chat Bot application. **/ +/** + * The entry point to the Google Chat Bot application. + * + *

The application itself exposes a number of REST endpoints accessible for the clients such as: + * + *

    + *
  • {@code /init} — triggers the initialization of the default resources the bot is + * monitoring. + *
  • {@code /chat/incoming/event} — handles incoming events from the Google Chat space. + *
  • {@code /repositories/check} — triggers checking of the repositories build statuses. + *
+ * + * @see InitController + * @see IncomingEventsController + * @see RepositoriesController + **/ public final class Application { static final String SERVER_NAME = "ChatBotServer"; From 857fc7c340472efa0f6f3a8e1a0dc97f07b04383 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:54:55 +0300 Subject: [PATCH 144/492] Treat warnings as errors --- buildSrc/src/main/kotlin/java-convention.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/java-convention.gradle.kts b/buildSrc/src/main/kotlin/java-convention.gradle.kts index c93a1262..11eca08e 100644 --- a/buildSrc/src/main/kotlin/java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/java-convention.gradle.kts @@ -55,7 +55,7 @@ tasks.compileJava { // Explicitly states the encoding of the source and test source files, ensuring // correct execution of the `javac` task. options.encoding = "UTF-8" - options.compilerArgs.addAll(listOf("-Xlint:unchecked", "-Xlint:deprecation")) + options.compilerArgs.addAll(listOf("-Xlint:unchecked", "-Xlint:deprecation", "-Werror")) // Configure Error Prone: // 1. Exclude generated sources from being analyzed by Error Prone. From 693928c11b84142fca2d55e6c54877d33c328f31 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:56:06 +0300 Subject: [PATCH 145/492] Suppress errorprone warning --- google-chat-bot/src/test/java/io/spine/net/UrlsTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java index d784e7ed..662d4032 100644 --- a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java @@ -42,6 +42,7 @@ final class UrlsTest extends UtilityClassTest { @DisplayName("compose URL for") @Nested + @SuppressWarnings("ClassCanBeStatic") // jUnit Jupiter cannot work with static classes final class Compose { @DisplayName("Travis CI repository page") From e076ab18c7d86f152872247229cef7b1a9678b63 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 17 Jun 2020 23:59:25 +0300 Subject: [PATCH 146/492] Add notion of the builds in the URL --- .../src/main/java/io/spine/chatbot/RepositoriesController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 79526b7e..514e65bd 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -38,7 +38,7 @@ public class RepositoriesController { /** * Sends {@link CheckRepositoryBuild} commands to all repositories registered in the system. */ - @Post("/check") + @Post("/builds/check") public String checkBuildStatuses() { var botClient = ChatBotClient.inProcessClient(SERVER_NAME); botClient.listRepositories() From 808949b3b083e22796b1b9659cc713b07d4cf4d0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 00:25:44 +0300 Subject: [PATCH 147/492] Add more logs --- .../src/main/java/io/spine/chatbot/InitController.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index 6cd0716a..6e20ff6a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -66,13 +66,14 @@ public String initWatchedResources(@QueryValue String spaceName) { return "Successfully initialized"; } - private static void registerWatchedRepos(ChatBotClient client, OrganizationId spineOrgId) { + private void registerWatchedRepos(ChatBotClient client, OrganizationId spineOrgId) { var watchedRepositories = defaultTravisClient() .queryRepositoriesFor(spineOrgId.getValue()) .getRepositoriesList() .stream() .filter(repository -> WATCHED_REPOS.contains(repository.getName())); watchedRepositories.forEach(repository -> { + _info().log("Registering repository `%s`.", repository.getName()); var registerRepository = registerRepoCommand(repository, spineOrgId); client.postSyncCommand(registerRepository, RepositoryRegistered.class); }); @@ -91,9 +92,10 @@ private static RegisterRepository registerRepoCommand(Repository repository, .vBuild(); } - private static void registerOrganization(ChatBotClient client, - OrganizationId spineOrgId, - String spaceName) { + private void registerOrganization(ChatBotClient client, + OrganizationId spineOrgId, + String spaceName) { + _info().log("Registering `Spine Event Engine` organization."); var registerSpineOrg = RegisterOrganization .newBuilder() .setName("Spine Event Engine") From fc48d43386c3fc0547a809b0d38006c9b33f3b76 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 00:36:39 +0300 Subject: [PATCH 148/492] Adding logs --- .../io/spine/chatbot/ChatBotServerEnvironment.java | 3 ++- .../io/spine/chatbot/IncomingEventsController.java | 10 +++++++--- .../src/main/java/io/spine/chatbot/InitController.java | 3 ++- .../java/io/spine/chatbot/RepositoriesController.java | 8 ++++++-- .../chatbot/server/github/OrganizationAggregate.java | 5 ++++- .../chatbot/server/github/RepositoryAggregate.java | 5 ++++- .../chatbot/server/google/chat/SpaceAggregate.java | 4 +++- .../chatbot/server/google/chat/ThreadAggregate.java | 9 +++++++-- .../chatbot/server/google/chat/ThreadChatProcess.java | 5 ++++- 9 files changed, 39 insertions(+), 13 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index c6377cf5..58614471 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -59,9 +59,10 @@ static void initializeEnvironment() { StorageFactory storageFactory = storageFactoryFor(environment); se.configureStorage(storageFactory); se.configureTransport(InMemoryTransportFactory.newInstance()); - se.configureDelivery(deliveryFor(environment, storageFactory)); + se.configureDelivery(Delivery.local()); } + @SuppressWarnings("unused") // we'll get back to DS-based delivery private static Delivery deliveryFor(Environment environment, StorageFactory storageFactory) { if (environment.isProduction()) { var dsStorageFactory = (DatastoreStorageFactory) storageFactory; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 4ce3e12d..c8543ee1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -55,22 +55,26 @@ public class IncomingEventsController implements Logging { public String on(@Body PubsubPushNotification pushNotification) { var message = pushNotification.getMessage(); var chatEventJson = decodeBase64Json(message.getData()); + _debug().log("Received a new chat event: %s", chatEventJson); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); switch (chatEvent.getType()) { case MESSAGE: + _info().log("Processing user message."); break; case ADDED_TO_SPACE: - onBotAddedToSpace(chatEvent.getSpace(), client); + var space = chatEvent.getSpace(); + _info().log("Bot added to space `%s` (%s).", + space.getDisplayName(), space.getName()); + onBotAddedToSpace(space, client); break; case REMOVED_FROM_SPACE: case CARD_CLICKED: case UNRECOGNIZED: case ET_UNKNOWN: - _warn().log("Unsupported chat event type received: %s", chatEvent.getType()); + _debug().log("Unsupported chat event type received: %s", chatEvent.getType()); break; } - _debug().log("Received a new Chat event: %s", chatEvent); return "OK"; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index 6e20ff6a..37c84b52 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -73,7 +73,8 @@ private void registerWatchedRepos(ChatBotClient client, OrganizationId spineOrgI .stream() .filter(repository -> WATCHED_REPOS.contains(repository.getName())); watchedRepositories.forEach(repository -> { - _info().log("Registering repository `%s`.", repository.getName()); + _info().log("Sending `RegisterRepository` command for repository `%s`.", + repository.getName()); var registerRepository = registerRepoCommand(repository, spineOrgId); client.postSyncCommand(registerRepository, RepositoryRegistered.class); }); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 514e65bd..8b28ec3a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -25,6 +25,7 @@ import io.spine.chatbot.client.ChatBotClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; +import io.spine.logging.Logging; import static io.spine.chatbot.Application.SERVER_NAME; import static io.spine.util.Exceptions.newIllegalStateException; @@ -33,20 +34,23 @@ * A REST controller handling Repository commands. */ @Controller("/repositories") -public class RepositoriesController { +public class RepositoriesController implements Logging { /** * Sends {@link CheckRepositoryBuild} commands to all repositories registered in the system. */ @Post("/builds/check") public String checkBuildStatuses() { + _debug().log("Checking repositories build statues."); var botClient = ChatBotClient.inProcessClient(SERVER_NAME); botClient.listRepositories() .forEach(repository -> checkBuildStatus(botClient, repository)); return "success"; } - private static void checkBuildStatus(ChatBotClient botClient, RepositoryId repository) { + private void checkBuildStatus(ChatBotClient botClient, RepositoryId repository) { + _info().log("Sending `CheckRepositoryBuild` command for repository `%s`", + repository.getValue()); var checkRepositoryBuild = checkRepoBuildCommand(repository); var subscriptions = botClient .asGuest() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 66500fef..8ed2b366 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -24,15 +24,18 @@ import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; final class OrganizationAggregate - extends Aggregate { + extends Aggregate + implements Logging { @Assign OrganizationRegistered handle(RegisterOrganization c) { + _info().log("Registering organization `%s`.", idAsString()); return OrganizationRegistered .newBuilder() .setId(c.getId()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java index f7c7b5e8..adc70c61 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -24,15 +24,18 @@ import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.github.repository.event.RepositoryRegistered; +import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; final class RepositoryAggregate - extends Aggregate { + extends Aggregate + implements Logging { @Assign RepositoryRegistered handle(RegisterRepository c) { + _info().log("Registering repository `%s`.", idAsString()); var result = RepositoryRegistered .newBuilder() .setId(c.getId()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 6dcfe51a..05e14135 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -24,14 +24,16 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; -final class SpaceAggregate extends Aggregate { +final class SpaceAggregate extends Aggregate implements Logging { @Assign SpaceRegistered handle(RegisterSpace c) { + _info().log("Registering space `%s`.", idAsString()); var result = SpaceRegistered .newBuilder() .setId(c.getId()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index d6a01516..50365b1b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -26,14 +26,16 @@ import io.spine.chatbot.google.chat.thread.Thread; import io.spine.chatbot.google.chat.thread.event.MessageAdded; import io.spine.chatbot.google.chat.thread.event.ThreadInitialized; +import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; import io.spine.server.event.React; -final class ThreadAggregate extends Aggregate { +final class ThreadAggregate extends Aggregate implements Logging { @React ThreadInitialized on(ThreadCreated e) { + _info().log("A new thread `%s` created.", idAsString()); return ThreadInitialized .newBuilder() .setId(e.getId()) @@ -50,9 +52,12 @@ private void on(ThreadInitialized e) { @React MessageAdded on(MessageCreated e) { + var messageId = e.getId(); + _info().log("A new message `%s` added to the thread `%s`.", + messageId.getValue(), idAsString()); return MessageAdded .newBuilder() - .setId(e.getId()) + .setId(messageId) .setThreadId(e.getThreadId()) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 0b3b4841..8fb96da7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -28,6 +28,7 @@ import io.spine.chatbot.google.chat.event.ThreadCreated; import io.spine.chatbot.google.chat.thread.ThreadChat; import io.spine.core.External; +import io.spine.logging.Logging; import io.spine.server.event.React; import io.spine.server.procman.ProcessManager; import io.spine.server.tuple.Pair; @@ -39,7 +40,8 @@ import static io.spine.chatbot.server.google.chat.Identifiers.newThreadId; import static io.spine.chatbot.server.google.chat.ThreadResources.newThreadResource; -final class ThreadChatProcess extends ProcessManager { +final class ThreadChatProcess extends ProcessManager + implements Logging { @React Pair> on(@External BuildStateChanged e) { @@ -49,6 +51,7 @@ Pair> on(@External BuildStateChanged e) var threadId = newThreadId(repositoryId.getValue()); var spaceId = newSpaceId(buildState.getGoogleChatSpace()); var currentThread = state().getThread(); + _info().log("Build state changed for the repository `%s`.", repositoryId.getValue()); var sentMessage = GoogleChatClient.sendBuildStateUpdate(buildState, currentThread.getName()); var thread = sentMessage.getThread(); From 5efc2fc291bd371c6e6edd632e2c5f3532e62ff4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 00:42:47 +0300 Subject: [PATCH 149/492] set GCP_PROJECT_ID during the deployment --- cloudbuild.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 82fae511..7c1bf4c0 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -10,6 +10,7 @@ steps: args: [ 'run', 'deploy', '${_SERVICE_NAME}', '--image', 'gcr.io/${PROJECT_ID}/${_SERVICE_NAME}', + '--set-env-vars', 'GCP_PROJECT_ID=${PROJECT_ID}', '--region', 'europe-west1', '--platform', 'managed', '--project', '${PROJECT_ID}' From bdf640f01fb7c3da7572ed9177415dff76402043 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 00:48:18 +0300 Subject: [PATCH 150/492] Add validations --- .../spine/chatbot/github/organization_commands.proto | 2 +- .../proto/spine/chatbot/github/organization_events.proto | 2 +- .../spine/chatbot/github/repository_build_commands.proto | 2 +- .../proto/spine/chatbot/github/repository_commands.proto | 2 +- .../proto/spine/chatbot/github/repository_events.proto | 2 +- .../proto/spine/chatbot/google/chat/chat_events.proto | 6 +++--- .../proto/spine/chatbot/google/chat/identifiers.proto | 4 ++-- .../proto/spine/chatbot/google/chat/thread_events.proto | 8 ++++---- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 7fac6b87..657c83ec 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -50,5 +50,5 @@ message RegisterOrganization { spine.net.Url travis_ci_url = 5 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 6 [(required) = true]; + string google_chat_space = 6 [(required) = true, (pattern).regex = "spaces/.+"]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index 4dbb2ecd..570b87b4 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -50,5 +50,5 @@ message OrganizationRegistered { spine.net.Url travis_ci_url = 5 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 6 [(required) = true]; + string google_chat_space = 6 [(required) = true, (pattern).regex = "spaces/.+"]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 00387711..201c3b00 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -36,5 +36,5 @@ import "spine/chatbot/github/identifiers.proto"; message CheckRepositoryBuild { // ID of the repository to perform a check for. - RepositoryId id = 1; + RepositoryId id = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index c1511e6a..2339b7ba 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -47,6 +47,6 @@ message RegisterRepository { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; - // ID of the organization repository is related to if any. + // ID of the organization the repository is related to if any. OrganizationId organization = 5; } \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 652ac117..ed1890fc 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -47,6 +47,6 @@ message RepositoryRegistered { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; - // ID of the organization repository is related to if any. + // ID of the organization the repository is related to if any. OrganizationId organization = 5; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index a51aaa76..4a6e68a8 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -47,11 +47,11 @@ message MessageCreated { // Denotes that a recently created message created a new thread. message ThreadCreated { - ThreadId id = 1; + ThreadId id = 1 [(required) = true]; // Google Chat thread. - ThreadResource thread = 2; + ThreadResource thread = 2 [(required) = true]; // ID of the space within with the thread is available. - SpaceId space_id = 3; + SpaceId space_id = 3 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto index 1aa3d945..70a408c3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -33,7 +33,7 @@ option java_multiple_files = true; message SpaceId { // Resource name of the space, in the form `spaces/`. - string value = 1 [(required) = true]; + string value = 1 [(required) = true, (pattern).regex = "spaces/.+"]; } // Hangouts Chat Room Thread identifier. @@ -50,5 +50,5 @@ message ThreadId { message MessageId { // Resource name of the message, in the form `spaces//messages/`. - string value = 1 [(required) = true]; + string value = 1 [(required) = true, (pattern).regex = "spaces/.+/messages/.+"]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index d91b7a09..5293e392 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -35,13 +35,13 @@ import "spine/chatbot/google/chat/thread.proto"; // Denotes that a message was created in the space. message ThreadInitialized { - ThreadId id = 1; + ThreadId id = 1 [(required) = true]; // Google Chat thread. - ThreadResource thread = 2; + ThreadResource thread = 2 [(required) = true]; - // ID of the space within with the thread is available. - SpaceId space_id = 3; + // ID of the space within which the thread is available. + SpaceId space_id = 3 [(required) = true]; } // Denotes that a message was created in the space. From 7da6f9bc7044c753cbc79be4d2c64b7143d7f422 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 11:15:33 +0300 Subject: [PATCH 151/492] Drop `new` usage in method names --- .../io/spine/chatbot/IncomingEventsController.java | 2 +- .../main/java/io/spine/chatbot/InitController.java | 8 ++++---- .../io/spine/chatbot/server/github/Identifiers.java | 6 +++--- .../chatbot/server/google/chat/Identifiers.java | 4 ++-- .../server/google/chat/ThreadChatProcess.java | 12 ++++++------ .../google/chat/ThreadChatProcessRepository.java | 4 ++-- .../chatbot/server/google/chat/ThreadResources.java | 2 +- .../server/github/OrganizationAggregateTest.java | 4 ++-- .../server/github/RepositoryAggregateTest.java | 8 ++++---- .../server/google/chat/ThreadAggregateTest.java | 6 +++--- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index c8543ee1..d6f90efc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -83,7 +83,7 @@ private static void onBotAddedToSpace(Space space, ChatBotClient client) { .newBuilder() .setDisplayName(space.getDisplayName()) .setThreaded(isThreaded(space)) - .setId(Identifiers.newSpaceId(space.getName())) + .setId(Identifiers.spaceIdOf(space.getName())) .vBuild(); client.postSyncCommand(registerSpace, SpaceRegistered.class); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index 37c84b52..c12c3e36 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -34,8 +34,8 @@ import io.spine.logging.Logging; import static io.spine.chatbot.api.TravisClient.defaultTravisClient; -import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; -import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; +import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; +import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; import static io.spine.net.Urls.githubRepoUrlFor; import static io.spine.net.Urls.travisRepoUrlFor; import static io.spine.net.Urls.urlOfSpec; @@ -60,7 +60,7 @@ public String initWatchedResources(@QueryValue String spaceName) { "Performing initial application state initialization in the Google Chat space `%s`", spaceName); var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); - var spineOrgId = newOrganizationId("SpineEventEngine"); + var spineOrgId = organizationIdOf("SpineEventEngine"); registerOrganization(client, spineOrgId, spaceName); registerWatchedRepos(client, spineOrgId); return "Successfully initialized"; @@ -87,7 +87,7 @@ private static RegisterRepository registerRepoCommand(Repository repository, .newBuilder() .setOrganization(orgId) .setGithubUrl(githubRepoUrlFor(slug)) - .setId(newRepositoryId(slug)) + .setId(repositoryIdOf(slug)) .setName(repository.getName()) .setTravisCiUrl(travisRepoUrlFor(slug)) .vBuild(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java index e8acb082..e52aae7e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java @@ -33,15 +33,15 @@ private Identifiers() { } /** Creates a new {@link OrganizationId} out of the specified {@code name}. **/ - public static OrganizationId newOrganizationId(String name) { + public static OrganizationId organizationIdOf(String name) { return OrganizationId .newBuilder() .setValue(name) .vBuild(); } - /** Creates a new {@link OrganizationId} out of the specified {@code slug}. **/ - public static RepositoryId newRepositoryId(String slug) { + /** Creates a new {@link RepositoryId} out of the specified {@code slug}. **/ + public static RepositoryId repositoryIdOf(String slug) { return RepositoryId .newBuilder() .setValue(slug) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java index 94de44ff..52bf936c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java @@ -36,7 +36,7 @@ private Identifiers() { } /** Creates a new {@link ThreadId} out of the specified {@code value}. **/ - public static ThreadId newThreadId(String value) { + public static ThreadId threadIdOf(String value) { checkNotNull(value); return ThreadId .newBuilder() @@ -45,7 +45,7 @@ public static ThreadId newThreadId(String value) { } /** Creates a new {@link SpaceId} out of the specified {@code value}. **/ - public static SpaceId newSpaceId(String value) { + public static SpaceId spaceIdOf(String value) { checkNotNull(value); return SpaceId .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 8fb96da7..b6f0346d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -36,9 +36,9 @@ import java.util.Optional; import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; -import static io.spine.chatbot.server.google.chat.Identifiers.newSpaceId; -import static io.spine.chatbot.server.google.chat.Identifiers.newThreadId; -import static io.spine.chatbot.server.google.chat.ThreadResources.newThreadResource; +import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; final class ThreadChatProcess extends ProcessManager implements Logging { @@ -48,8 +48,8 @@ Pair> on(@External BuildStateChanged e) var change = e.getChange(); var buildState = change.getNewValue(); var repositoryId = e.getId(); - var threadId = newThreadId(repositoryId.getValue()); - var spaceId = newSpaceId(buildState.getGoogleChatSpace()); + var threadId = threadIdOf(repositoryId.getValue()); + var spaceId = spaceIdOf(buildState.getGoogleChatSpace()); var currentThread = state().getThread(); _info().log("Build state changed for the repository `%s`.", repositoryId.getValue()); var sentMessage = GoogleChatClient.sendBuildStateUpdate(buildState, @@ -63,7 +63,7 @@ Pair> on(@External BuildStateChanged e) .setThreadId(threadId) .vBuild(); if (Strings.isNullOrEmpty(currentThread.getName())) { - var newThread = newThreadResource(thread.getName()); + var newThread = threadResourceOf(thread.getName()); builder().setThread(newThread) .setSpaceId(spaceId); var threadCreated = ThreadCreated diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java index 33503752..a85fa4e3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -27,7 +27,7 @@ import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.route.EventRouting; -import static io.spine.chatbot.server.google.chat.Identifiers.newThreadId; +import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; import static io.spine.server.route.EventRoute.withId; final class ThreadChatProcessRepository @@ -39,7 +39,7 @@ protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); routing.route(BuildStateChanged.class, (event, context) -> { var repositoryId = event.getId(); - var id = newThreadId(repositoryId.getValue()); + var id = threadIdOf(repositoryId.getValue()); return withId(id); }); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java index 3e1ee038..3f904ed4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -34,7 +34,7 @@ private ThreadResources() { } /** Creates a new {@link ThreadResource} with the specified {@code name}. **/ - public static ThreadResource newThreadResource(String name) { + public static ThreadResource threadResourceOf(String name) { return ThreadResource .newBuilder() .setName(name) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 3081d586..1fc9640a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -32,7 +32,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; +import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") @@ -47,7 +47,7 @@ protected BoundedContextBuilder contextBuilder() { @DisplayName("register an organization") final class Register { - private final OrganizationId organizationId = newOrganizationId("TestOrganization"); + private final OrganizationId organizationId = organizationIdOf("TestOrganization"); private final Url githubUrl = urlOfSpec("https://github.com/TestOrganization"); private final Url travisCiUrl = urlOfSpec("https://travis-ci.com/TestOrganization"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 523ec8d1..8e536fe7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -33,8 +33,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.Identifiers.newOrganizationId; -import static io.spine.chatbot.server.github.Identifiers.newRepositoryId; +import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; +import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") @@ -49,8 +49,8 @@ protected BoundedContextBuilder contextBuilder() { @DisplayName("register a repository") final class Register { - private final RepositoryId repositoryId = newRepositoryId("SpineEventEngine/base"); - private final OrganizationId organizationId = newOrganizationId("SpineEventEngine"); + private final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/base"); + private final OrganizationId organizationId = organizationIdOf("SpineEventEngine"); private final Url githubUrl = urlOfSpec("https://github.com/SpineEventEngine/base"); private final Url travisCiUrl = diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index b3fa4e00..c95bcd72 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; -import static io.spine.chatbot.server.google.chat.ThreadResources.newThreadResource; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") final class ThreadAggregateTest extends ContextAwareTest { @@ -58,7 +58,7 @@ final class InitThread { .setValue("spaces/qpojdwpiq1241") .vBuild(); private final ThreadResource threadResource = - newThreadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); + threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); @BeforeEach void setUp() { @@ -109,7 +109,7 @@ final class AddMessage { private final MessageId messageId = newMessageId("spaces/qpojdwpiq1241/messages/dqpwjpop12"); private final ThreadResource threadResource = - newThreadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); + threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); @BeforeEach void setUp() { From dfaeb33579dc2026a984432b0b2c0cb194aafb06 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 11:15:46 +0300 Subject: [PATCH 152/492] Add missing EOL --- .idea/misc.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 868b4d01..4937397c 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -59,4 +59,4 @@
-
\ No newline at end of file + From 73c430a9ae99d8ba0ddbf653d22d98abb0722c55 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 11:17:13 +0300 Subject: [PATCH 153/492] Fix misprint --- .../src/main/java/io/spine/chatbot/client/ChatBotClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java index 21c32129..d22880b6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -57,7 +57,7 @@ public static ChatBotClient inProcessClient(String serverName) { return new ChatBotClient(client); } - /** Returns Spine client quest request. **/ + /** Returns Spine client guest request. **/ public ClientRequest asGuest() { return client.asGuest(); } From d3c53687388ab3365d9486d7042808c059fe6fb4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 11:50:40 +0300 Subject: [PATCH 154/492] Extract Spine deliveries into a sub-package --- .../chatbot/ChatBotServerEnvironment.java | 49 ++++--------- .../chatbot/delivery/DeliveryFactory.java | 49 +++++++++++++ .../chatbot/delivery/DsDeliveryFactory.java | 69 ++++++++++++++++++ .../delivery/LocalDeliveryFactory.java | 70 +++++++++++++++++++ .../spine/chatbot/delivery/ShardDelivery.java | 47 +++++++++++++ .../spine/chatbot/delivery/package-info.java | 30 ++++++++ .../java/io/spine/chatbot/package-info.java | 2 +- 7 files changed, 279 insertions(+), 37 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index 58614471..e3601474 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -22,13 +22,10 @@ import com.google.cloud.datastore.DatastoreOptions; import io.spine.base.Environment; +import io.spine.chatbot.delivery.DeliveryFactory; import io.spine.server.ServerEnvironment; -import io.spine.server.delivery.Delivery; -import io.spine.server.delivery.UniformAcrossAllShards; import io.spine.server.storage.StorageFactory; import io.spine.server.storage.datastore.DatastoreStorageFactory; -import io.spine.server.storage.datastore.DsShardedWorkRegistry; -import io.spine.server.storage.memory.InMemoryStorageFactory; import io.spine.server.transport.memory.InMemoryTransportFactory; /** @@ -46,9 +43,7 @@ final class ChatBotServerEnvironment { private static final int NUMBER_OF_SHARDS = 50; - /** - * Prevents instantiation of this utility class. - */ + /** Prevents instantiation of this utility class. **/ private ChatBotServerEnvironment() { } @@ -56,38 +51,20 @@ private ChatBotServerEnvironment() { static void initializeEnvironment() { var se = ServerEnvironment.instance(); var environment = Environment.instance(); - StorageFactory storageFactory = storageFactoryFor(environment); + var storageFactory = dsStorageFactory(); + var deliveryFactory = DeliveryFactory.instance(environment, storageFactory); + var delivery = deliveryFactory.delivery(); se.configureStorage(storageFactory); se.configureTransport(InMemoryTransportFactory.newInstance()); - se.configureDelivery(Delivery.local()); + se.configureDelivery(delivery); } - @SuppressWarnings("unused") // we'll get back to DS-based delivery - private static Delivery deliveryFor(Environment environment, StorageFactory storageFactory) { - if (environment.isProduction()) { - var dsStorageFactory = (DatastoreStorageFactory) storageFactory; - var workRegistry = new DsShardedWorkRegistry(dsStorageFactory); - var inboxStorage = dsStorageFactory.createInboxStorage(false); - var delivery = Delivery - .newBuilder() - .setStrategy(UniformAcrossAllShards.forNumber(NUMBER_OF_SHARDS)) - .setWorkRegistry(workRegistry) - .setInboxStorage(inboxStorage) - .build(); - return delivery; - } - return Delivery.local(); - } - - private static StorageFactory storageFactoryFor(Environment environment) { - if (environment.isProduction()) { - var datastore = DatastoreOptions.getDefaultInstance() - .getService(); - return DatastoreStorageFactory - .newBuilder() - .setDatastore(datastore) - .build(); - } - return InMemoryStorageFactory.newInstance(); + private static DatastoreStorageFactory dsStorageFactory() { + var datastore = DatastoreOptions.getDefaultInstance() + .getService(); + return DatastoreStorageFactory + .newBuilder() + .setDatastore(datastore) + .build(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java new file mode 100644 index 00000000..a3eee3b7 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.delivery; + +import io.spine.base.Environment; +import io.spine.server.delivery.Delivery; +import io.spine.server.storage.datastore.DatastoreStorageFactory; + +/** + * A utility class for configuring {@link Delivery} for environments. + */ +public interface DeliveryFactory { + + /** + * Creates a new fully-configured delivery. + */ + Delivery delivery(); + + /** + * Creates a new instance of a delivery factory for the specified {@code environment} + * and using the {@code storageFactory} if required. + */ + static DeliveryFactory instance(Environment environment, + DatastoreStorageFactory storageFactory) { + if (environment.isProduction()) { + return DsDeliveryFactory.instance(storageFactory); + } else { + return LocalDeliveryFactory.instance; + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java new file mode 100644 index 00000000..9a16bed3 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.delivery; + +import io.spine.server.delivery.Delivery; +import io.spine.server.delivery.ShardedWorkRegistry; +import io.spine.server.delivery.UniformAcrossAllShards; +import io.spine.server.storage.datastore.DatastoreStorageFactory; +import io.spine.server.storage.datastore.DsShardedWorkRegistry; + +/** + * A {@link Delivery} factory that creates deliveries used in distributed cloud environments. + * + *

The distributed delivery is based on {@link DatastoreStorageFactory datastore}. + * + *

Uses {@link DsShardedWorkRegistry} as the {@link ShardedWorkRegistry}. + */ +final class DsDeliveryFactory implements DeliveryFactory { + + /** The number of shards used for the signals delivery. **/ + private static final int NUMBER_OF_SHARDS = 50; + + private final DatastoreStorageFactory storageFactory; + + private DsDeliveryFactory(DatastoreStorageFactory factory) { + storageFactory = factory; + } + + /** Creates a new instance of the delivery factory. **/ + static DeliveryFactory instance(DatastoreStorageFactory storageFactory) { + return new DsDeliveryFactory(storageFactory); + } + + /** + * Creates a new Datastore-based delivery using the supplied Datastore {@code storageFactory}. + * + *

Uses uniformly sharded strategy and single-tenant inbox storage. + */ + @Override + public Delivery delivery() { + var workRegistry = new DsShardedWorkRegistry(storageFactory); + var inboxStorage = storageFactory.createInboxStorage(false); + var delivery = Delivery + .newBuilder() + .setStrategy(UniformAcrossAllShards.forNumber(NUMBER_OF_SHARDS)) + .setWorkRegistry(workRegistry) + .setInboxStorage(inboxStorage) + .build(); + return delivery; + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java new file mode 100644 index 00000000..0132b8b0 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java @@ -0,0 +1,70 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.delivery; + +import com.google.protobuf.util.Durations; +import io.spine.server.delivery.CatchUpStorage; +import io.spine.server.delivery.Delivery; +import io.spine.server.delivery.InboxStorage; +import io.spine.server.delivery.UniformAcrossAllShards; +import io.spine.server.delivery.memory.InMemoryShardedWorkRegistry; +import io.spine.server.storage.memory.InMemoryCatchUpStorage; +import io.spine.server.storage.memory.InMemoryInboxStorage; + +/** + * A {@link Delivery} factory that creates deliveries for local or test environments. + */ +final class LocalDeliveryFactory implements DeliveryFactory { + + /** A singleton instance of the local delivery factory. **/ + static final LocalDeliveryFactory instance = new LocalDeliveryFactory(); + + /** Prevents instantiation of this class. **/ + private LocalDeliveryFactory() { + } + + /** + * Creates a new instance of an in-memory local delivery. + */ + @Override + public Delivery delivery() { + var delivery = Delivery + .newBuilder() + .setInboxStorage(singleTenantInboxStorage()) + .setCatchUpStorage(singleTenantCatchupStorage()) + .setWorkRegistry(new InMemoryShardedWorkRegistry()) + .setStrategy(UniformAcrossAllShards.singleShard()) + .setDeduplicationWindow(Durations.fromSeconds(0)) + .build(); + delivery.subscribe(ShardDelivery::deliver); + return delivery; + } + + @SuppressWarnings("TestOnlyProblems") // we do want the in-memory delivery in local-dev env + private static InboxStorage singleTenantInboxStorage() { + return new InMemoryInboxStorage(false); + } + + @SuppressWarnings("TestOnlyProblems") // we do want the in-memory delivery in local-dev env + private static CatchUpStorage singleTenantCatchupStorage() { + return new InMemoryCatchUpStorage(false); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java new file mode 100644 index 00000000..8624e3f1 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -0,0 +1,47 @@ +package io.spine.chatbot.delivery; + +import io.spine.logging.Logging; +import io.spine.server.ServerEnvironment; +import io.spine.server.delivery.DeliveryStats; +import io.spine.server.delivery.ShardIndex; +import io.spine.server.delivery.ShardedRecord; + +/** + * Delivery of messages from a particular shard. + */ +final class ShardDelivery implements Logging { + + private final ShardIndex shard; + + private ShardDelivery(ShardIndex shard) { + this.shard = shard; + } + + /** Delivers the {@code message}. **/ + static void deliver(ShardedRecord message) { + deliverFrom(message.shardIndex()); + } + + /** Delivers messages from the {@code shard}. **/ + static void deliverFrom(ShardIndex shard) { + var delivery = new ShardDelivery(shard); + delivery.deliverNow(); + } + + private void deliverNow() { + var server = ServerEnvironment.instance(); + var nodeId = server.nodeId().getValue(); + var indexValue = shard.getIndex(); + _trace().log("Delivering messages from shard with index `%d`. NodeId=%s.", + indexValue, nodeId); + var stats = server.delivery().deliverMessagesFrom(shard); + if (stats.isPresent()) { + DeliveryStats deliveryStats = stats.get(); + _trace().log("`%d` messages delivered from shard with index `%s`. NodeId=%s.", + deliveryStats.deliveredCount(), indexValue, nodeId); + } else { + _trace().log("No messages delivered from shard with index `%d`. NodeId=%s.", + indexValue, nodeId); + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java new file mode 100644 index 00000000..35b379c6 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains Spine's Google Chat Bot signals delivery configurations. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.delivery; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java index cd6e4d2a..b417bbbf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java @@ -19,7 +19,7 @@ */ /** - * This package Spine's Google Chat Bot application and environment configurations. + * This contains package Spine's Google Chat Bot application and environment configurations. */ @CheckReturnValue @ParametersAreNonnullByDefault From 80dae877be5e457a79db811a1fc0023aee950a4d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 14:51:59 +0300 Subject: [PATCH 155/492] Remove obsolete constant and add link to DeliveryFactory --- .../main/java/io/spine/chatbot/ChatBotServerEnvironment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index e3601474..6a1ee06f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -38,11 +38,11 @@ * *

Configures the inbox delivery through the Datastore work registry while * in Production environment, otherwise uses local synchronous delivery. + * + * @see DeliveryFactory */ final class ChatBotServerEnvironment { - private static final int NUMBER_OF_SHARDS = 50; - /** Prevents instantiation of this utility class. **/ private ChatBotServerEnvironment() { } From 9c4b1d3d7522e675fed4bb5320ac6c7e03e03242 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 14:59:19 +0300 Subject: [PATCH 156/492] Reduce controllers visibility --- .../src/main/java/io/spine/chatbot/BeanFactory.java | 4 ++-- .../main/java/io/spine/chatbot/IncomingEventsController.java | 4 ++-- .../src/main/java/io/spine/chatbot/InitController.java | 2 +- .../main/java/io/spine/chatbot/RepositoriesController.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 91e54de7..c9695663 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -30,7 +30,7 @@ * Creates Micronaut context bean definitions. */ @Factory -public class BeanFactory { +final class BeanFactory { /** * Registers {@link com.google.pubsub.v1.PubsubPushNotification push notification} @@ -38,7 +38,7 @@ public class BeanFactory { */ @Singleton @Bean - public PubsubPushNotificationDeserializer pubsubDeserializer() { + PubsubPushNotificationDeserializer pubsubDeserializer() { return new PubsubPushNotificationDeserializer(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index d6f90efc..f723132a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -44,7 +44,7 @@ * A REST controller for handling incoming events from Google Chat. */ @Controller("/chat") -public class IncomingEventsController implements Logging { +final class IncomingEventsController implements Logging { /** * Processes an incoming Google Chat event. @@ -52,7 +52,7 @@ public class IncomingEventsController implements Logging { *

When a bot is added to a new space, registers the space in the system. */ @Post(value = "/incoming/event", consumes = APPLICATION_JSON) - public String on(@Body PubsubPushNotification pushNotification) { + String on(@Body PubsubPushNotification pushNotification) { var message = pushNotification.getMessage(); var chatEventJson = decodeBase64Json(message.getData()); _debug().log("Received a new chat event: %s", chatEventJson); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java index c12c3e36..dae05b78 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java @@ -44,7 +44,7 @@ * A REST controller for handling initialization of the application state. */ @Controller("/init") -public class InitController implements Logging { +class InitController implements Logging { private static final ImmutableList WATCHED_REPOS = ImmutableList.of( "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 8b28ec3a..2b0d37a5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -34,13 +34,13 @@ * A REST controller handling Repository commands. */ @Controller("/repositories") -public class RepositoriesController implements Logging { +final class RepositoriesController implements Logging { /** * Sends {@link CheckRepositoryBuild} commands to all repositories registered in the system. */ @Post("/builds/check") - public String checkBuildStatuses() { + String checkBuildStatuses() { _debug().log("Checking repositories build statues."); var botClient = ChatBotClient.inProcessClient(SERVER_NAME); botClient.listRepositories() From 2cddda9c7ae5f3de040779caf7a97b7a0d76dc2d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 15:04:41 +0300 Subject: [PATCH 157/492] drop usage of `new` in methods --- .../java/io/spine/chatbot/server/google/chat/Identifiers.java | 2 +- .../spine/chatbot/server/google/chat/ThreadChatProcess.java | 4 ++-- .../spine/chatbot/server/google/chat/ThreadAggregateTest.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java index 52bf936c..1510de76 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java @@ -54,7 +54,7 @@ public static SpaceId spaceIdOf(String value) { } /** Creates a new {@link MessageId} out of the specified {@code value}. **/ - public static MessageId newMessageId(String value) { + public static MessageId messageIdOf(String value) { checkNotNull(value); return MessageId .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index b6f0346d..b7e08d6e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -35,7 +35,7 @@ import java.util.Optional; -import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; +import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @@ -55,7 +55,7 @@ Pair> on(@External BuildStateChanged e) var sentMessage = GoogleChatClient.sendBuildStateUpdate(buildState, currentThread.getName()); var thread = sentMessage.getThread(); - var messageId = newMessageId(sentMessage.getName()); + var messageId = messageIdOf(sentMessage.getName()); var messageCreated = MessageCreated .newBuilder() .setId(messageId) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index c95bcd72..ff9f97c3 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -36,7 +36,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.Identifiers.newMessageId; +import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") @@ -107,7 +107,7 @@ final class AddMessage { .setValue("spaces/qpojdwpiq1241") .vBuild(); private final MessageId messageId = - newMessageId("spaces/qpojdwpiq1241/messages/dqpwjpop12"); + messageIdOf("spaces/qpojdwpiq1241/messages/dqpwjpop12"); private final ThreadResource threadResource = threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); From b5685594cccb3c18d00178ab59d3d626c7fa379a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 15:46:25 +0300 Subject: [PATCH 158/492] Add `@Command` to entry points --- .idea/misc.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 4937397c..05eabd13 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,11 +1,12 @@ - + - + + @@ -59,4 +60,4 @@ - + \ No newline at end of file From 5a7b5803e9a4ce9bab9ecca4c37e8f7edafdeb57 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 15:47:21 +0300 Subject: [PATCH 159/492] Create Organization init process --- .../chatbot/github/organization_init.proto | 50 +++++++++++++++++++ .../github/organization_init_commands.proto | 42 ++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto new file mode 100644 index 00000000..a0fe604a --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -0,0 +1,50 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.organization.init"; +option java_outer_classname = "OrganizationInitProto"; +option java_multiple_files = true; + +import "spine/chatbot/github/identifiers.proto"; + +// The initialization process of the default watched organization resources. +// +// Ensures that watched resources organization and its repositories are initialized +// for a particular Chat Space. +message OrganizationInit { + option (entity).kind = PROCESS_MANAGER; + option (entity).visibility = FULL; + + // The ID of the organization for which the initialization is performed. + OrganizationId id = 1; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 2; + + // Determines whether the organization resources are already initialized. + bool is_initialized = 3; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto new file mode 100644 index 00000000..74beecf3 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.organization.init.command"; +option java_outer_classname = "OrganizationInitCommandsProto"; +option java_multiple_files = true; + +import "spine/chatbot/github/identifiers.proto"; + +// Requests a check of the repository CI build. +message InitializeOrganization { + + // ID of the organization to perform initialization for. + OrganizationId id = 1 [(required) = true]; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 2 [(required) = true, (pattern).regex = "spaces/.+"]; +} From 14bf8493b4a345575d59318fe4bf711079914b3e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 15:50:18 +0300 Subject: [PATCH 160/492] Create stub org init process --- .../chatbot/server/github/GitHubContext.java | 3 +- .../github/OrganizationInitProcess.java | 100 ++++++++++++++++++ .../github/OrganizationInitRepository.java | 42 ++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 8135163d..ac154da2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -86,6 +86,7 @@ public static BoundedContextBuilder newBuilder() { .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) .add(RepositoryBuildProcess.class) - .add(new OrganizationRepositoriesRepository()); + .add(new OrganizationRepositoriesRepository()) + .add(new OrganizationInitRepository()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java new file mode 100644 index 00000000..73343688 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java @@ -0,0 +1,100 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import io.spine.base.CommandMessage; +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.chatbot.github.organization.init.OrganizationInit; +import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.travis.Repository; +import io.spine.core.External; +import io.spine.logging.Logging; +import io.spine.server.command.Command; +import io.spine.server.procman.ProcessManager; + +import static io.spine.chatbot.api.TravisClient.defaultTravisClient; +import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; +import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.net.Urls.githubRepoUrlFor; +import static io.spine.net.Urls.travisRepoUrlFor; +import static io.spine.net.Urls.urlOfSpec; + +final class OrganizationInitProcess + extends ProcessManager + implements Logging { + + private static final String SPINE_ORG = "SpineEventEngine"; + + private static final ImmutableList WATCHED_REPOS = ImmutableList.of( + "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" + ); + static final OrganizationId SPINE_ORGANIZATION = organizationIdOf(SPINE_ORG); + + @Command + Iterable on(@External SpaceRegistered e) { + if (state().getIsInitialized()) { + return ImmutableSet.of(); + } + var spaceId = e.getId(); + var commands = ImmutableSet.builder(); + commands.add(registerOrganizationCommand(SPINE_ORGANIZATION, spaceId.getValue())); + defaultTravisClient() + .queryRepositoriesFor(SPINE_ORG) + .getRepositoriesList() + .stream() + .filter(repository -> WATCHED_REPOS.contains(repository.getName())) + .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) + .forEach(commands::add); + var result = commands.build(); + return result; + } + + private static RegisterRepository registerRepoCommand(Repository repository, + OrganizationId orgId) { + var slug = repository.getSlug(); + return RegisterRepository + .newBuilder() + .setOrganization(orgId) + .setGithubUrl(githubRepoUrlFor(slug)) + .setId(repositoryIdOf(slug)) + .setName(repository.getName()) + .setTravisCiUrl(travisRepoUrlFor(slug)) + .vBuild(); + } + + private RegisterOrganization registerOrganizationCommand(OrganizationId spineOrgId, + String spaceName) { + _info().log("Registering `Spine Event Engine` organization."); + return RegisterOrganization + .newBuilder() + .setName("Spine Event Engine") + .setWebsiteUrl(urlOfSpec("https://spine.io/")) + .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine")) + .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine")) + .setId(spineOrgId) + .setGoogleChatSpace(spaceName) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java new file mode 100644 index 00000000..2f9e6a98 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.init.OrganizationInit; +import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.server.procman.ProcessManagerRepository; +import io.spine.server.route.EventRouting; + +import static io.spine.chatbot.server.github.OrganizationInitProcess.SPINE_ORGANIZATION; +import static io.spine.server.route.EventRoute.withId; + +final class OrganizationInitRepository + extends ProcessManagerRepository { + + @OverridingMethodsMustInvokeSuper + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(SpaceRegistered.class, (event, context) -> withId(SPINE_ORGANIZATION)); + } +} From 4557063ede9ec09b1751a4f9835e782b0ef65299 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 15:50:58 +0300 Subject: [PATCH 161/492] Drop init controller in favor of the init process --- .../java/io/spine/chatbot/Application.java | 3 - .../java/io/spine/chatbot/InitController.java | 111 ------------------ 2 files changed, 114 deletions(-) delete mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/InitController.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 2b4ddacf..9af3e068 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -34,13 +34,10 @@ *

The application itself exposes a number of REST endpoints accessible for the clients such as: * *

    - *
  • {@code /init} — triggers the initialization of the default resources the bot is - * monitoring. *
  • {@code /chat/incoming/event} — handles incoming events from the Google Chat space. *
  • {@code /repositories/check} — triggers checking of the repositories build statuses. *
* - * @see InitController * @see IncomingEventsController * @see RepositoriesController **/ diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java b/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java deleted file mode 100644 index dae05b78..00000000 --- a/google-chat-bot/src/main/java/io/spine/chatbot/InitController.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.chatbot; - -import com.google.common.collect.ImmutableList; -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Get; -import io.micronaut.http.annotation.QueryValue; -import io.spine.chatbot.client.ChatBotClient; -import io.spine.chatbot.github.OrganizationId; -import io.spine.chatbot.github.organization.command.RegisterOrganization; -import io.spine.chatbot.github.organization.event.OrganizationRegistered; -import io.spine.chatbot.github.repository.command.RegisterRepository; -import io.spine.chatbot.github.repository.event.RepositoryRegistered; -import io.spine.chatbot.travis.Repository; -import io.spine.logging.Logging; - -import static io.spine.chatbot.api.TravisClient.defaultTravisClient; -import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; -import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; -import static io.spine.net.Urls.githubRepoUrlFor; -import static io.spine.net.Urls.travisRepoUrlFor; -import static io.spine.net.Urls.urlOfSpec; - -/** - * A REST controller for handling initialization of the application state. - */ -@Controller("/init") -class InitController implements Logging { - - private static final ImmutableList WATCHED_REPOS = ImmutableList.of( - "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" - ); - - /** - * Performs the initial registration of the default Spine resources the bot is going - * to watch for for a particular Google Chat space. - */ - @Get - public String initWatchedResources(@QueryValue String spaceName) { - _info().log( - "Performing initial application state initialization in the Google Chat space `%s`", - spaceName); - var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); - var spineOrgId = organizationIdOf("SpineEventEngine"); - registerOrganization(client, spineOrgId, spaceName); - registerWatchedRepos(client, spineOrgId); - return "Successfully initialized"; - } - - private void registerWatchedRepos(ChatBotClient client, OrganizationId spineOrgId) { - var watchedRepositories = defaultTravisClient() - .queryRepositoriesFor(spineOrgId.getValue()) - .getRepositoriesList() - .stream() - .filter(repository -> WATCHED_REPOS.contains(repository.getName())); - watchedRepositories.forEach(repository -> { - _info().log("Sending `RegisterRepository` command for repository `%s`.", - repository.getName()); - var registerRepository = registerRepoCommand(repository, spineOrgId); - client.postSyncCommand(registerRepository, RepositoryRegistered.class); - }); - } - - private static RegisterRepository registerRepoCommand(Repository repository, - OrganizationId orgId) { - var slug = repository.getSlug(); - return RegisterRepository - .newBuilder() - .setOrganization(orgId) - .setGithubUrl(githubRepoUrlFor(slug)) - .setId(repositoryIdOf(slug)) - .setName(repository.getName()) - .setTravisCiUrl(travisRepoUrlFor(slug)) - .vBuild(); - } - - private void registerOrganization(ChatBotClient client, - OrganizationId spineOrgId, - String spaceName) { - _info().log("Registering `Spine Event Engine` organization."); - var registerSpineOrg = RegisterOrganization - .newBuilder() - .setName("Spine Event Engine") - .setWebsiteUrl(urlOfSpec("https://spine.io/")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine")) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine")) - .setId(spineOrgId) - .setGoogleChatSpace(spaceName) - .vBuild(); - client.postSyncCommand(registerSpineOrg, OrganizationRegistered.class); - } -} From 9d29c459f4e072a31d41c75c47aef98f201be7e9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 16:39:54 +0300 Subject: [PATCH 162/492] Extract TravisClient interface --- .../java/io/spine/chatbot/api/Travis.java | 109 ++++++++++++++++++ .../io/spine/chatbot/api/TravisClient.java | 77 +------------ 2 files changed, 112 insertions(+), 74 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java new file mode 100644 index 00000000..be2bdb07 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java @@ -0,0 +1,109 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.protobuf.Message; +import io.spine.chatbot.travis.BuildsResponse; +import io.spine.chatbot.travis.RepositoriesResponse; + +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.nio.charset.StandardCharsets; + +import static io.spine.chatbot.api.JsonProtoBodyHandler.jsonBodyHandler; +import static java.lang.String.format; + +/** + * A Travis CI REST API client. + * + * @see Travis CI API + */ +public final class Travis implements TravisClient { + + private static final HttpClient CLIENT = HttpClient.newHttpClient(); + private static final String BASE_URL = "https://api.travis-ci.com"; + private static final String API_HEADER = "Travis-API-Version"; + private static final String API_VERSION = "3"; + private static final String AUTH_HEADER = "Authorization"; + + private final String apiToken; + + /** + * Creates a new Travis client with the specified API token. + */ + private Travis(String token) { + apiToken = token; + } + + /** + * Creates a new Travis client with the default secure Travis token. + */ + public static TravisClient defaultTravisClient() { + return new Travis(Secrets.travisToken()); + } + + @Override + public BuildsResponse queryBuildsFor(String repoSlug) { + var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); + var repositoryBuildsQuery = "/repo/" + + encodedSlug + + "/builds?limit=1&branch.name=master&include=build.commit"; + var result = queryForResponse(repositoryBuildsQuery, BuildsResponse.class); + return result; + } + + @Override + public RepositoriesResponse queryRepositoriesFor(String owner) { + var encodedOwner = URLEncoder.encode(owner, StandardCharsets.UTF_8); + var ownerRepositoriesQuery = "/owner/" + encodedOwner + "/repos"; + var result = queryForResponse(ownerRepositoriesQuery, RepositoriesResponse.class); + return result; + } + + private T queryForResponse(String query, Class responseType) { + var request = apiRequest(query, apiToken); + try { + var result = CLIENT.send(request, jsonBodyHandler(responseType)); + return result.body(); + } catch (IOException | InterruptedException e) { + var message = format("Unable to query data for response of type '%s' using query '%s'.", + responseType, query); + throw new RuntimeException(message, e); + } + } + + private static HttpRequest apiRequest(String apiPath, String token) { + return authorizedApiRequest(token) + .uri(URI.create(BASE_URL + apiPath)) + .build(); + } + + private static HttpRequest.Builder authorizedApiRequest(String token) { + return HttpRequest + .newBuilder() + .GET() + .header(API_HEADER, API_VERSION) + .header(AUTH_HEADER, "token " + token); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java index b193df94..3e626863 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java @@ -20,94 +20,23 @@ package io.spine.chatbot.api; -import com.google.protobuf.Message; import io.spine.chatbot.travis.BuildsResponse; import io.spine.chatbot.travis.RepositoriesResponse; -import java.io.IOException; -import java.net.URI; -import java.net.URLEncoder; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.nio.charset.StandardCharsets; - -import static io.spine.chatbot.api.JsonProtoBodyHandler.jsonBodyHandler; -import static java.lang.String.format; - /** * A Travis CI API client. * * @see Travis CI API */ -public final class TravisClient { - - private static final HttpClient CLIENT = HttpClient.newHttpClient(); - private static final String BASE_URL = "https://api.travis-ci.com"; - private static final String API_HEADER = "Travis-API-Version"; - private static final String API_VERSION = "3"; - private static final String AUTH_HEADER = "Authorization"; - - private final String apiToken; - - /** - * Creates a new Travis client with the specified API token. - */ - private TravisClient(String token) { - apiToken = token; - } - - /** - * Creates a new Travis client with the default secure Travis token. - */ - public static TravisClient defaultTravisClient() { - return new TravisClient(Secrets.travisToken()); - } +public interface TravisClient { /** * Queries Travis CI build statuses for a repository determined by the supplied repository slug. */ - public BuildsResponse queryBuildsFor(String repoSlug) { - var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); - var repositoryBuildsQuery = "/repo/" - + encodedSlug - + "/builds?limit=1&branch.name=master&include=build.commit"; - var result = queryForResponse(repositoryBuildsQuery, BuildsResponse.class); - return result; - } + BuildsResponse queryBuildsFor(String repoSlug); /** * Queries Travis CI repositories information for a specified {@code owner}. */ - public RepositoriesResponse queryRepositoriesFor(String owner) { - var encodedOwner = URLEncoder.encode(owner, StandardCharsets.UTF_8); - var ownerRepositoriesQuery = "/owner/" + encodedOwner + "/repos"; - var result = queryForResponse(ownerRepositoriesQuery, RepositoriesResponse.class); - return result; - } - - private T queryForResponse(String query, Class responseType) { - var request = apiRequest(query, apiToken); - try { - var result = CLIENT.send(request, jsonBodyHandler(responseType)); - return result.body(); - } catch (IOException | InterruptedException e) { - var message = format("Unable to query data for response of type '%s' using query '%s'.", - responseType, query); - throw new RuntimeException(message, e); - } - } - - private static HttpRequest apiRequest(String apiPath, String token) { - return authorizedApiRequest(token) - .uri(URI.create(BASE_URL + apiPath)) - .build(); - } - - private static HttpRequest.Builder authorizedApiRequest(String token) { - return HttpRequest - .newBuilder() - .GET() - .header(API_HEADER, API_VERSION) - .header(AUTH_HEADER, "token " + token); - } + RepositoriesResponse queryRepositoriesFor(String owner); } From 9ca287e65fbd8af3dfa18deaf806b348cc8c9b09 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 18:02:35 +0300 Subject: [PATCH 163/492] Refactor configuration of the GitHubContext. Add ability to supply custom Travis CI client. --- .../java/io/spine/chatbot/Application.java | 5 +- .../chatbot/server/github/GitHubContext.java | 95 ++++++++++--------- .../github/OrganizationInitProcess.java | 24 +++-- .../github/OrganizationInitRepository.java | 12 +++ .../server/github/RepositoryBuildProcess.java | 16 +++- .../github/RepositoryBuildRepository.java | 42 ++++++++ .../chatbot/api/InMemoryTravisClient.java | 74 +++++++++++++++ .../server/github/GitHubContextTest.java | 28 +++++- .../chatbot/server/github/GitHubTest.java | 52 ++++++++++ .../github/OrganizationAggregateTest.java | 9 +- .../github/RepositoryAggregateTest.java | 9 +- 11 files changed, 289 insertions(+), 77 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 9af3e068..b675f7df 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -59,9 +59,12 @@ public static void main(String[] args) { @VisibleForTesting static void initializeSpine() { ChatBotServerEnvironment.initializeEnvironment(); + var gitHubContext = GitHubContext + .newBuilder() + .build(); Server server = Server .inProcess(SERVER_NAME) - .add(GitHubContext.newBuilder()) + .add(gitHubContext.contextBuilder()) .add(GoogleChatContext.newBuilder()) .build(); try { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index ac154da2..b9540db7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -20,25 +20,19 @@ package io.spine.chatbot.server.github; -import com.google.errorprone.annotations.concurrent.LazyInit; +import io.spine.chatbot.api.Travis; +import io.spine.chatbot.api.TravisClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; -import io.spine.server.QueryService; -import io.spine.server.commandbus.CommandBus; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + +import static com.google.common.base.Preconditions.checkNotNull; /** * Provides {@link BoundedContextBuilder} for the GitHub context. */ public final class GitHubContext { - @MonotonicNonNull - @LazyInit - private static BoundedContext context = null; - - @MonotonicNonNull - @LazyInit - private static QueryService queryService = null; + private final BoundedContextBuilder contextBuilder; /** * The name of the Context. @@ -46,47 +40,60 @@ public final class GitHubContext { static final String NAME = "GitHub"; /** Prevents instantiation of this utility class. **/ - private GitHubContext() { - } - - /** Returns command bus associated with the bounded context. **/ - public static CommandBus commandBus() { - return context().commandBus(); - } - - /** Returns query service associated with the bounded context. **/ - public static synchronized QueryService queryService() { - if (queryService == null) { - queryService = QueryService - .newBuilder() - .add(context()) - .build(); - } - return queryService; - } - - /** Returns the bounded context. **/ - public static synchronized BoundedContext context() { - if (context == null) { - context = newBuilder().build(); - } - return context; + private GitHubContext(TravisClient travisClient) { + this.contextBuilder = configureContextBuilder(travisClient); } - /** Initializes bounded context and associated services. **/ - @SuppressWarnings("ResultOfMethodCallIgnored") - public static void initialize() { - queryService(); + /** Returns the context builder associated with the GitHub context. **/ + public BoundedContextBuilder contextBuilder() { + return this.contextBuilder; } - /** Creates a new instance of the GitHub Context builder. **/ - public static BoundedContextBuilder newBuilder() { + private static BoundedContextBuilder configureContextBuilder(TravisClient travisClient) { return BoundedContext .singleTenant(NAME) .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) - .add(RepositoryBuildProcess.class) .add(new OrganizationRepositoriesRepository()) - .add(new OrganizationInitRepository()); + .add(new OrganizationInitRepository(travisClient)) + .add(new RepositoryBuildRepository(travisClient)); + } + + /** + * Creates a new builder of the GitHub context. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** A Builder for configuring GitHub context. **/ + public static final class Builder { + + private TravisClient travisClient; + + private Builder() { + } + + /** + * Sets a Travis CI client to be used within the context. + */ + public Builder setTravis(TravisClient travisClient) { + checkNotNull(travisClient); + this.travisClient = travisClient; + return this; + } + + /** + * Finishes configuration of the GitHub context and builds a new instance. + * + *

If the {@link #travisClient} was not explicitly configured, uses the + * {@link Travis#defaultTravisClient() default} client. + */ + public GitHubContext build() { + if (travisClient == null) { + travisClient = Travis.defaultTravisClient(); + } + return new GitHubContext(travisClient); + } } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java index 73343688..ff421cde 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java @@ -22,7 +22,9 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; +import io.spine.chatbot.api.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; @@ -33,8 +35,8 @@ import io.spine.logging.Logging; import io.spine.server.command.Command; import io.spine.server.procman.ProcessManager; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.api.TravisClient.defaultTravisClient; import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; import static io.spine.net.Urls.githubRepoUrlFor; @@ -52,6 +54,9 @@ final class OrganizationInitProcess ); static final OrganizationId SPINE_ORGANIZATION = organizationIdOf(SPINE_ORG); + @LazyInit + private @MonotonicNonNull TravisClient travisClient; + @Command Iterable on(@External SpaceRegistered e) { if (state().getIsInitialized()) { @@ -60,13 +65,12 @@ Iterable on(@External SpaceRegistered e) { var spaceId = e.getId(); var commands = ImmutableSet.builder(); commands.add(registerOrganizationCommand(SPINE_ORGANIZATION, spaceId.getValue())); - defaultTravisClient() - .queryRepositoriesFor(SPINE_ORG) - .getRepositoriesList() - .stream() - .filter(repository -> WATCHED_REPOS.contains(repository.getName())) - .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) - .forEach(commands::add); + travisClient.queryRepositoriesFor(SPINE_ORG) + .getRepositoriesList() + .stream() + .filter(repository -> WATCHED_REPOS.contains(repository.getName())) + .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) + .forEach(commands::add); var result = commands.build(); return result; } @@ -97,4 +101,8 @@ private RegisterOrganization registerOrganizationCommand(OrganizationId spineOrg .setGoogleChatSpace(spaceName) .vBuild(); } + + void setTravisClient(TravisClient travisClient) { + this.travisClient = travisClient; + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java index 2f9e6a98..ceafef34 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.github; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.api.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.event.SpaceRegistered; @@ -33,10 +34,21 @@ final class OrganizationInitRepository extends ProcessManagerRepository { + private final TravisClient travisClient; + + OrganizationInitRepository(TravisClient travisClient) { + this.travisClient = travisClient; + } + @OverridingMethodsMustInvokeSuper @Override protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); routing.route(SpaceRegistered.class, (event, context) -> withId(SPINE_ORGANIZATION)); } + + @Override + protected void configure(OrganizationInitProcess processManager) { + processManager.setTravisClient(travisClient); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index f7e0814b..7ae0a4ae 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -20,7 +20,9 @@ package io.spine.chatbot.server.github; +import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; +import io.spine.chatbot.api.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; @@ -32,18 +34,20 @@ import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.api.TravisClient.defaultTravisClient; import static io.spine.net.Urls.travisBuildUrlFor; final class RepositoryBuildProcess extends ProcessManager { + @LazyInit + private @MonotonicNonNull TravisClient travisClient; + @Assign BuildStateChanged handle(CheckRepositoryBuild c) { - var travis = defaultTravisClient(); - var builds = travis.queryBuildsFor(id().getValue()) - .getBuildsList(); + var builds = travisClient.queryBuildsFor(id().getValue()) + .getBuildsList(); if (builds.isEmpty()) { throw new RuntimeException("No builds available for repository " + idAsString()); } @@ -91,4 +95,8 @@ private static BuildState.Commit from(Commit commit) { .setCompareUrl(Urls.urlOfSpec(commit.getCompareUrl())) .vBuild(); } + + void setTravisClient(TravisClient travisClient) { + this.travisClient = travisClient; + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java new file mode 100644 index 00000000..25fdd28c --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.build.RepositoryBuild; +import io.spine.server.procman.ProcessManagerRepository; + +final class RepositoryBuildRepository + extends ProcessManagerRepository { + + private final TravisClient travisClient; + + RepositoryBuildRepository(TravisClient client) { + travisClient = client; + } + + @Override + protected void configure(RepositoryBuildProcess processManager) { + super.configure(processManager); + processManager.setTravisClient(travisClient); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java new file mode 100644 index 00000000..b89684cc --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java @@ -0,0 +1,74 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import io.spine.chatbot.travis.BuildsResponse; +import io.spine.chatbot.travis.RepositoriesResponse; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An in-memory test-only implementation of the Travis CI API client. + */ +public final class InMemoryTravisClient implements TravisClient { + + private final Map buildsResponses = new ConcurrentHashMap<>(); + private final Map repositoriesResponses = new ConcurrentHashMap<>(); + + @Override + public BuildsResponse queryBuildsFor(String repoSlug) { + checkNotNull(repoSlug); + var result = buildsResponses.get(repoSlug); + checkNotNull(result, "Builds response is not configured for the repository " + repoSlug); + return result; + } + + @Override + public RepositoriesResponse queryRepositoriesFor(String owner) { + checkNotNull(owner); + var result = repositoriesResponses.get(owner); + checkNotNull(result, "Repositories response is not configured for the owner " + owner); + return result; + } + + /** Sets up a mocked {@code builds} response for a specified {@code repoSlug}. **/ + public void setBuildsFor(String repoSlug, BuildsResponse builds) { + checkNotNull(repoSlug); + checkNotNull(builds); + buildsResponses.put(repoSlug, builds); + } + + /** Sets up a mocked {@code repositories} response for a specified {@code owner}. **/ + public void setRepositoriesFor(String owner, RepositoriesResponse repositories) { + checkNotNull(owner); + checkNotNull(repositories); + repositoriesResponses.put(owner, repositories); + } + + /** Resets state of the configured responses. **/ + public void reset() { + buildsResponses.clear(); + repositoriesResponses.clear(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java index 871a91cd..5c1486d9 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -20,13 +20,33 @@ package io.spine.chatbot.server.github; -import io.spine.testing.UtilityClassTest; +import io.spine.chatbot.api.InMemoryTravisClient; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; @DisplayName("GitHubContext should") -final class GitHubContextTest extends UtilityClassTest { +final class GitHubContextTest { + + @Test + @DisplayName("allow configuring Travis CI client") + void allowConfiguringTravisClient() { + assertDoesNotThrow( + () -> GitHubContext.newBuilder() + .setTravis(new InMemoryTravisClient()) + .build() + ); + } - GitHubContextTest() { - super(GitHubContext.class); + @SuppressWarnings({"ResultOfMethodCallIgnored", "ConstantConditions"}) + @Test + @DisplayName("not allow passing `null` value as Travis CI client") + void notAllowNullTravisClients() { + assertThrows( + NullPointerException.class, () -> GitHubContext.newBuilder() + .setTravis(null) + ); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java new file mode 100644 index 00000000..029d4a62 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.api.InMemoryTravisClient; +import io.spine.server.BoundedContextBuilder; +import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.AfterEach; + +/** + * An abstract test-base for GitHub context tests. + */ +class GitHubTest extends ContextAwareTest { + + final InMemoryTravisClient travisClient = new InMemoryTravisClient(); + + @Override + protected BoundedContextBuilder contextBuilder() { + return GitHubContext + .newBuilder() + .setTravis(travisClient) + .build() + .contextBuilder(); + } + + @AfterEach + @OverridingMethodsMustInvokeSuper + @Override + protected void closeContext() { + super.closeContext(); + travisClient.reset(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 1fc9640a..1def3de1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -25,8 +25,6 @@ import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.event.OrganizationRegistered; import io.spine.net.Url; -import io.spine.server.BoundedContextBuilder; -import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -36,12 +34,7 @@ import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") -final class OrganizationAggregateTest extends ContextAwareTest { - - @Override - protected BoundedContextBuilder contextBuilder() { - return GitHubContext.newBuilder(); - } +final class OrganizationAggregateTest extends GitHubTest { @Nested @DisplayName("register an organization") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 8e536fe7..13120d5d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -26,8 +26,6 @@ import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.github.repository.event.RepositoryRegistered; import io.spine.net.Url; -import io.spine.server.BoundedContextBuilder; -import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -38,12 +36,7 @@ import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") -final class RepositoryAggregateTest extends ContextAwareTest { - - @Override - protected BoundedContextBuilder contextBuilder() { - return GitHubContext.newBuilder(); - } +final class RepositoryAggregateTest extends GitHubTest { @Nested @DisplayName("register a repository") From f5da730cc182362c11745401197bf327ca73d19d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 18:09:59 +0300 Subject: [PATCH 164/492] Add Organization init process test --- .../github/OrganizationInitProcess.java | 5 +- .../github/OrganizationInitProcessTest.java | 87 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java index ff421cde..a69d4b4c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java @@ -71,8 +71,9 @@ Iterable on(@External SpaceRegistered e) { .filter(repository -> WATCHED_REPOS.contains(repository.getName())) .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) .forEach(commands::add); - var result = commands.build(); - return result; + builder().setGoogleChatSpace(spaceId.getValue()) + .setIsInitialized(true); + return commands.build(); } private static RegisterRepository registerRepoCommand(Repository repository, diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java new file mode 100644 index 00000000..cb1d678f --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.organization.init.OrganizationInit; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.server.google.chat.Identifiers; +import io.spine.chatbot.travis.RepositoriesResponse; +import io.spine.chatbot.travis.Repository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.github.OrganizationInitProcess.SPINE_ORGANIZATION; + +@DisplayName("OrganizationInitProcess should") +final class OrganizationInitProcessTest extends GitHubTest { + + @DisplayName("perform initialization of watched spine resources") + @Nested + class Init { + + private final SpaceId spaceId = Identifiers.spaceIdOf("spaces/qjwrp1441"); + private final Repository repository = Repository + .newBuilder() + .setId(123312L) + .setName("time") + .setSlug("SpineEventEngine/time") + .vBuild(); + + @BeforeEach + void setUp() { + var repositoriesResponse = RepositoriesResponse + .newBuilder() + .addRepositories(repository) + .vBuild(); + travisClient.setRepositoriesFor(SPINE_ORGANIZATION.getValue(), repositoriesResponse); + var spaceRegistered = SpaceRegistered + .newBuilder() + .setId(spaceId) + .setDisplayName("Test space") + .setThreaded(true) + .vBuild(); + context().receivesExternalEvent(spaceRegistered); + } + + @Test + @DisplayName("setting process state") + void settingState() { + var expectedState = OrganizationInit + .newBuilder() + .setGoogleChatSpace(spaceId.getValue()) + .setIsInitialized(true) + .setId(SPINE_ORGANIZATION) + .vBuild(); + context().assertState(SPINE_ORGANIZATION, OrganizationInit.class) + .isEqualTo(expectedState); + } + + @Test + @DisplayName("producing commands to register organization and repositories") + void producingCommands() { + context().assertCommands() + .hasSize(2); + } + } +} From 2cf2a6c6be26f843525b9e5721721649226ec5ea Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 18:35:41 +0300 Subject: [PATCH 165/492] Refactor GoogleChatContext to allow configuring API clients as we now do for GitHubContext. --- .../java/io/spine/chatbot/Application.java | 15 +++- .../chatbot/server/github/GitHubContext.java | 14 ++-- .../server/google/chat/GoogleChatContext.java | 73 ++++++++----------- .../chatbot/IncomingEventsControllerTest.java | 14 +++- .../chatbot/api/InMemoryTravisClient.java | 36 ++++++++- .../server/github/GitHubContextTest.java | 2 +- .../chatbot/server/github/GitHubTest.java | 2 +- .../server/google/chat/GoogleChatTest.java | 38 ++++++++++ .../google/chat/SpaceAggregateTest.java | 13 +--- .../google/chat/ThreadAggregateTest.java | 38 ++++------ 10 files changed, 147 insertions(+), 98 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index b675f7df..b4211f51 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -56,16 +56,25 @@ public static void main(String[] args) { } /** Initializes Spine server environment and starts Spine {@link Server}. **/ - @VisibleForTesting - static void initializeSpine() { + private static void initializeSpine() { ChatBotServerEnvironment.initializeEnvironment(); var gitHubContext = GitHubContext .newBuilder() .build(); + var googleChatContext = GoogleChatContext + .newBuilder() + .build(); + startSpineServer(gitHubContext, googleChatContext); + } + + /** Starts Spine in-process server. **/ + @VisibleForTesting + static void startSpineServer(GitHubContext gitHubContext, + GoogleChatContext googleChatContext) { Server server = Server .inProcess(SERVER_NAME) .add(gitHubContext.contextBuilder()) - .add(GoogleChatContext.newBuilder()) + .add(googleChatContext.contextBuilder()) .build(); try { server.start(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index b9540db7..4f1225fb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -32,13 +32,13 @@ */ public final class GitHubContext { - private final BoundedContextBuilder contextBuilder; - /** * The name of the Context. */ static final String NAME = "GitHub"; + private final BoundedContextBuilder contextBuilder; + /** Prevents instantiation of this utility class. **/ private GitHubContext(TravisClient travisClient) { this.contextBuilder = configureContextBuilder(travisClient); @@ -59,9 +59,7 @@ private static BoundedContextBuilder configureContextBuilder(TravisClient travis .add(new RepositoryBuildRepository(travisClient)); } - /** - * Creates a new builder of the GitHub context. - */ + /** Creates a new builder of the GitHub context. **/ public static Builder newBuilder() { return new Builder(); } @@ -74,9 +72,7 @@ public static final class Builder { private Builder() { } - /** - * Sets a Travis CI client to be used within the context. - */ + /** Sets Travis CI client to be used within the context. **/ public Builder setTravis(TravisClient travisClient) { checkNotNull(travisClient); this.travisClient = travisClient; @@ -84,7 +80,7 @@ public Builder setTravis(TravisClient travisClient) { } /** - * Finishes configuration of the GitHub context and builds a new instance. + * Finishes configuration of the context and builds a new instance. * *

If the {@link #travisClient} was not explicitly configured, uses the * {@link Travis#defaultTravisClient() default} client. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 553d1958..2fea54f7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -20,71 +20,56 @@ package io.spine.chatbot.server.google.chat; -import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; -import io.spine.server.QueryService; -import io.spine.server.commandbus.CommandBus; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * Provides {@link BoundedContextBuilder} for the Google Chat context. */ public final class GoogleChatContext { - @MonotonicNonNull - @LazyInit - private static BoundedContext context = null; - - @MonotonicNonNull - @LazyInit - private static QueryService queryService = null; - - /** - * The name of the Context. - */ + /** The name of the Context. **/ static final String NAME = "GoogleChat"; + private final BoundedContextBuilder contextBuilder; + /** Prevents instantiation of this utility class. **/ private GoogleChatContext() { + this.contextBuilder = configureContextBuilder(); } - /** Returns command bus associated with the bounded context. **/ - public static CommandBus commandBus() { - return context().commandBus(); - } - - /** Returns query service associated with the bounded context. **/ - public static synchronized QueryService queryService() { - if (queryService == null) { - queryService = QueryService - .newBuilder() - .add(context()) - .build(); - } - return queryService; - } - - /** Returns the bounded context. **/ - public static synchronized BoundedContext context() { - if (context == null) { - context = newBuilder().build(); - } - return context; - } - - /** Initializes bounded context and associated services. **/ - @SuppressWarnings("ResultOfMethodCallIgnored") - public static void initialize() { - queryService(); + /** Returns the context builder associated with the Google Chat context. **/ + public BoundedContextBuilder contextBuilder() { + return this.contextBuilder; } /** Creates a new instance of the Google Chat context builder. **/ - public static BoundedContextBuilder newBuilder() { + private static BoundedContextBuilder configureContextBuilder() { return BoundedContext .singleTenant(NAME) .add(SpaceAggregate.class) .add(new ThreadAggregateRepository()) .add(new ThreadChatProcessRepository()); } + + /** Creates a new builder of the Google Chat context. **/ + public static Builder newBuilder() { + return new Builder(); + } + + /** A Builder for configuring Google Chat context. **/ + public static final class Builder { + + //TODO:2020-06-18:ysergiichuk: add ability to configure GoogleChatClient + + private Builder() { + } + + /** + * Finishes configuration of the context and builds a new instance. + */ + public GoogleChatContext build() { + return new GoogleChatContext(); + } + } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 3c5ef2ee..4ca999a5 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -28,6 +28,9 @@ import io.micronaut.http.client.annotation.Client; import io.micronaut.runtime.server.EmbeddedServer; import io.micronaut.test.annotation.MicronautTest; +import io.spine.chatbot.api.InMemoryTravisClient; +import io.spine.chatbot.server.github.GitHubContext; +import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.json.Json; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -38,7 +41,7 @@ import java.util.Base64; import static io.micronaut.http.HttpRequest.POST; -import static io.spine.chatbot.Application.initializeSpine; +import static io.spine.chatbot.Application.startSpineServer; import static org.junit.jupiter.api.Assertions.assertEquals; @DisplayName("IncomingEventsController should") @@ -54,7 +57,14 @@ final class IncomingEventsControllerTest { @BeforeAll static void setupServer() { - initializeSpine(); + var chatContext = GoogleChatContext + .newBuilder() + .build(); + var gitHubContext = GitHubContext + .newBuilder() + .setTravis(InMemoryTravisClient.lenientClient()) + .build(); + startSpineServer(gitHubContext, chatContext); } @Test diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java index b89684cc..b8c40831 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java @@ -27,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Exceptions.newIllegalStateException; /** * An in-memory test-only implementation of the Travis CI API client. @@ -36,11 +37,35 @@ public final class InMemoryTravisClient implements TravisClient { private final Map buildsResponses = new ConcurrentHashMap<>(); private final Map repositoriesResponses = new ConcurrentHashMap<>(); + /** Determines whether the client should fail if a particular response was not preconfigured. **/ + private final boolean failFast; + + private InMemoryTravisClient(boolean failFast) { + this.failFast = failFast; + } + + /** Creates a {@link #failFast} in-memory Travis CI client. **/ + public static InMemoryTravisClient strictClient() { + return new InMemoryTravisClient(true); + } + + /** Creates a lenient in-memory Travis CI client. **/ + public static InMemoryTravisClient lenientClient() { + return new InMemoryTravisClient(false); + } + @Override public BuildsResponse queryBuildsFor(String repoSlug) { checkNotNull(repoSlug); var result = buildsResponses.get(repoSlug); - checkNotNull(result, "Builds response is not configured for the repository " + repoSlug); + if (failFast && result == null) { + throw newIllegalStateException( + "Builds response is not configured for the repository `%s`.", repoSlug + ); + } + if (!failFast && result == null) { + result = BuildsResponse.getDefaultInstance(); + } return result; } @@ -48,7 +73,14 @@ public BuildsResponse queryBuildsFor(String repoSlug) { public RepositoriesResponse queryRepositoriesFor(String owner) { checkNotNull(owner); var result = repositoriesResponses.get(owner); - checkNotNull(result, "Repositories response is not configured for the owner " + owner); + if (failFast && result == null) { + throw newIllegalStateException( + "Repositories response is not configured for the owner `%s`.", owner + ); + } + if (!failFast && result == null) { + result = RepositoriesResponse.getDefaultInstance(); + } return result; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java index 5c1486d9..f2dc87ec 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -35,7 +35,7 @@ final class GitHubContextTest { void allowConfiguringTravisClient() { assertDoesNotThrow( () -> GitHubContext.newBuilder() - .setTravis(new InMemoryTravisClient()) + .setTravis(InMemoryTravisClient.lenientClient()) .build() ); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java index 029d4a62..20443cb6 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java @@ -31,7 +31,7 @@ */ class GitHubTest extends ContextAwareTest { - final InMemoryTravisClient travisClient = new InMemoryTravisClient(); + final InMemoryTravisClient travisClient = InMemoryTravisClient.strictClient(); @Override protected BoundedContextBuilder contextBuilder() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java new file mode 100644 index 00000000..ae86feff --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.server.BoundedContextBuilder; +import io.spine.testing.server.blackbox.ContextAwareTest; + +/** + * An abstract test-base for Google Chat context tests. + */ +class GoogleChatTest extends ContextAwareTest { + + @Override + protected BoundedContextBuilder contextBuilder() { + return GoogleChatContext + .newBuilder() + .build() + .contextBuilder(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 7d58cb30..12c3a318 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -24,28 +24,19 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; -import io.spine.server.BoundedContextBuilder; -import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @DisplayName("SpaceAggregate should") -final class SpaceAggregateTest extends ContextAwareTest { - - @Override - protected BoundedContextBuilder contextBuilder() { - return GoogleChatContext.newBuilder(); - } +final class SpaceAggregateTest extends GoogleChatTest { @Nested @DisplayName("register a space") final class Register { - private final SpaceId spaceId = SpaceId.newBuilder() - .setValue("spaces/poqwdpQ21") - .vBuild(); + private final SpaceId spaceId = Identifiers.spaceIdOf("spaces/poqwdpQ21"); private final String displayName = "Spine Developers"; @BeforeEach diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index ff9f97c3..5bbc2194 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -29,34 +29,25 @@ import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.chatbot.google.chat.thread.event.MessageAdded; import io.spine.chatbot.google.chat.thread.event.ThreadInitialized; -import io.spine.server.BoundedContextBuilder; -import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") -final class ThreadAggregateTest extends ContextAwareTest { - - @Override - protected BoundedContextBuilder contextBuilder() { - return GoogleChatContext.newBuilder(); - } +final class ThreadAggregateTest extends GoogleChatTest { @Nested @DisplayName("initialize a thread") final class InitThread { - private final ThreadId threadId = ThreadId.newBuilder() - .setValue("SpineEventEngine/base") - .vBuild(); - private final SpaceId spaceId = SpaceId.newBuilder() - .setValue("spaces/qpojdwpiq1241") - .vBuild(); + private final ThreadId threadId = threadIdOf("SpineEventEngine/base"); + private final SpaceId spaceId = spaceIdOf("spaces/qpojdwpiq1241"); private final ThreadResource threadResource = threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); @@ -86,11 +77,12 @@ void producingEvent() { @Test @DisplayName("setting aggregate state") void settingState() { - var state = Thread.newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResource) - .vBuild(); + var state = Thread + .newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResource) + .vBuild(); context().assertState(threadId, Thread.class) .isEqualTo(state); } @@ -100,12 +92,8 @@ void settingState() { @DisplayName("add created message") final class AddMessage { - private final ThreadId threadId = ThreadId.newBuilder() - .setValue("SpineEventEngine/base") - .vBuild(); - private final SpaceId spaceId = SpaceId.newBuilder() - .setValue("spaces/qpojdwpiq1241") - .vBuild(); + private final ThreadId threadId = threadIdOf("SpineEventEngine/base"); + private final SpaceId spaceId = spaceIdOf("spaces/qpojdwpiq1241"); private final MessageId messageId = messageIdOf("spaces/qpojdwpiq1241/messages/dqpwjpop12"); private final ThreadResource threadResource = From e817ee752ba3bea153433467cef4992127ba6a7c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 18 Jun 2020 19:51:51 +0300 Subject: [PATCH 166/492] Use latest bootstrap plugin version --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b6696305..b23968e3 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { implementation("net.ltgt.gradle:gradle-apt-plugin:0.21") implementation("com.github.jengelman.gradle.plugins:shadow:5.2.0") implementation("gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.4.0") - implementation("io.spine.tools:spine-bootstrap:1.5.17") + implementation("io.spine.tools:spine-bootstrap:1.5.21") implementation("net.saliman:gradle-properties-plugin:1.5.1") } From ceb2b39468b389f81298ec332facd41401196264 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 12:18:11 +0300 Subject: [PATCH 167/492] Add ability to stub GoogleChatClient for tests --- .../java/io/spine/chatbot/api/GoogleChat.java | 96 +++++++++++++++++++ .../spine/chatbot/api/GoogleChatClient.java | 59 +----------- .../server/google/chat/GoogleChatContext.java | 27 ++++-- .../server/google/chat/ThreadChatProcess.java | 11 ++- .../chat/ThreadChatProcessRepository.java | 12 +++ .../io/spine/chatbot/api/FailFastClient.java | 74 ++++++++++++++ .../chatbot/api/InMemoryGoogleChatClient.java | 74 ++++++++++++++ .../chatbot/api/InMemoryTravisClient.java | 34 ++----- .../google/chat/GoogleChatContextTest.java | 29 +++++- .../server/google/chat/GoogleChatTest.java | 10 ++ 10 files changed, 335 insertions(+), 91 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java new file mode 100644 index 00000000..40806d7c --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java @@ -0,0 +1,96 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.chat.v1.HangoutsChat; +import com.google.api.services.chat.v1.model.Message; +import com.google.auth.http.HttpCredentialsAdapter; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.chatbot.github.repository.build.BuildState; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.security.GeneralSecurityException; + +import static io.spine.chatbot.api.BuildStateUpdates.buildStateMessage; + +/** + * Google Chat Hangouts API client. + * + * @see Hangouts Chat API + */ +public final class GoogleChat implements GoogleChatClient { + + private static final String BOT_NAME = "Spine Chat Bot"; + private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; + + private final HangoutsChat hangoutsChat; + + private GoogleChat(HangoutsChat chat) { + hangoutsChat = chat; + } + + /** + * Creates default Google Chat client. + */ + public static GoogleChatClient defaultGoogleChatClient() { + return new GoogleChat(hangoutsChat()); + } + + @Override + public Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { + var message = buildStateMessage(buildState, threadName); + return sendMessage(buildState.getGoogleChatSpace(), message); + } + + @CanIgnoreReturnValue + private Message sendMessage(String space, Message message) { + try { + return hangoutsChat + .spaces() + .messages() + .create(space, message) + .execute(); + } catch (IOException e) { + throw new RuntimeException("Unable to send message to space " + space, e); + } + } + + private static HangoutsChat hangoutsChat() { + try { + var credentials = GoogleCredentials.getApplicationDefault() + .createScoped(CHAT_BOT_SCOPE); + var credentialsAdapter = new HttpCredentialsAdapter(credentials); + var chat = new HangoutsChat.Builder( + GoogleNetHttpTransport.newTrustedTransport(), + JacksonFactory.getDefaultInstance(), + credentialsAdapter) + .setApplicationName(BOT_NAME) + .build(); + return chat; + } catch (IOException | GeneralSecurityException e) { + throw new RuntimeException("Unable to create Hangouts Chat client", e); + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index 9f6f17ae..b483d505 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -20,34 +20,18 @@ package io.spine.chatbot.api; -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.services.chat.v1.HangoutsChat; import com.google.api.services.chat.v1.model.Message; -import com.google.auth.http.HttpCredentialsAdapter; -import com.google.auth.oauth2.GoogleCredentials; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.build.BuildState; import javax.annotation.Nullable; -import java.io.IOException; -import java.security.GeneralSecurityException; - -import static io.spine.chatbot.api.BuildStateUpdates.buildStateMessage; /** - * Google Chat client. + * Google Chat API client abstraction. * - * @see Hangouts Chat API + *

Abstracts out usage of the chat API by exposing only ready-to-use ChatBot-specific + * methods. */ -public final class GoogleChatClient { - - private static final String BOT_NAME = "Spine Chat Bot"; - private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; - - /** Prevents direct instantiation. **/ - private GoogleChatClient() { - } +public interface GoogleChatClient { /** * Sends {@link BuildState} status message to a related space and thread. @@ -56,38 +40,5 @@ private GoogleChatClient() { * * @return a sent message */ - public static Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { - var message = buildStateMessage(buildState, threadName); - return sendMessage(hangoutsChat(), buildState.getGoogleChatSpace(), message); - } - - private static HangoutsChat hangoutsChat() { - try { - var credentials = GoogleCredentials.getApplicationDefault() - .createScoped(CHAT_BOT_SCOPE); - var credentialsAdapter = new HttpCredentialsAdapter(credentials); - var chat = new HangoutsChat.Builder( - GoogleNetHttpTransport.newTrustedTransport(), - JacksonFactory.getDefaultInstance(), - credentialsAdapter) - .setApplicationName(BOT_NAME) - .build(); - return chat; - } catch (IOException | GeneralSecurityException e) { - throw new RuntimeException("Unable to create Hangouts Chat client", e); - } - } - - @CanIgnoreReturnValue - private static Message sendMessage(HangoutsChat chat, String space, Message message) { - try { - return chat - .spaces() - .messages() - .create(space, message) - .execute(); - } catch (IOException e) { - throw new RuntimeException("Unable to send message to space " + space, e); - } - } + Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 2fea54f7..f4702cd8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -20,9 +20,13 @@ package io.spine.chatbot.server.google.chat; +import io.spine.chatbot.api.GoogleChat; +import io.spine.chatbot.api.GoogleChatClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Provides {@link BoundedContextBuilder} for the Google Chat context. */ @@ -34,8 +38,8 @@ public final class GoogleChatContext { private final BoundedContextBuilder contextBuilder; /** Prevents instantiation of this utility class. **/ - private GoogleChatContext() { - this.contextBuilder = configureContextBuilder(); + private GoogleChatContext(GoogleChatClient googleChatClient) { + this.contextBuilder = configureContextBuilder(googleChatClient); } /** Returns the context builder associated with the Google Chat context. **/ @@ -44,12 +48,13 @@ public BoundedContextBuilder contextBuilder() { } /** Creates a new instance of the Google Chat context builder. **/ - private static BoundedContextBuilder configureContextBuilder() { + private static BoundedContextBuilder + configureContextBuilder(GoogleChatClient googleChatClient) { return BoundedContext .singleTenant(NAME) .add(SpaceAggregate.class) .add(new ThreadAggregateRepository()) - .add(new ThreadChatProcessRepository()); + .add(new ThreadChatProcessRepository(googleChatClient)); } /** Creates a new builder of the Google Chat context. **/ @@ -60,16 +65,26 @@ public static Builder newBuilder() { /** A Builder for configuring Google Chat context. **/ public static final class Builder { - //TODO:2020-06-18:ysergiichuk: add ability to configure GoogleChatClient + private GoogleChatClient googleChatClient; private Builder() { } + /** Sets Google Chat client to be used within the context. **/ + public Builder setGoogleChatClient(GoogleChatClient googleChatClient) { + checkNotNull(googleChatClient); + this.googleChatClient = googleChatClient; + return this; + } + /** * Finishes configuration of the context and builds a new instance. */ public GoogleChatContext build() { - return new GoogleChatContext(); + if (googleChatClient == null) { + googleChatClient = GoogleChat.defaultGoogleChatClient(); + } + return new GoogleChatContext(googleChatClient); } } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index b7e08d6e..34e7e337 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.google.chat; import com.google.common.base.Strings; +import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.chatbot.api.GoogleChatClient; import io.spine.chatbot.github.repository.build.event.BuildStateChanged; import io.spine.chatbot.google.chat.ThreadId; @@ -32,6 +33,7 @@ import io.spine.server.event.React; import io.spine.server.procman.ProcessManager; import io.spine.server.tuple.Pair; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import java.util.Optional; @@ -43,6 +45,9 @@ final class ThreadChatProcess extends ProcessManager implements Logging { + @LazyInit + private @MonotonicNonNull GoogleChatClient googleChatClient; + @React Pair> on(@External BuildStateChanged e) { var change = e.getChange(); @@ -52,7 +57,7 @@ Pair> on(@External BuildStateChanged e) var spaceId = spaceIdOf(buildState.getGoogleChatSpace()); var currentThread = state().getThread(); _info().log("Build state changed for the repository `%s`.", repositoryId.getValue()); - var sentMessage = GoogleChatClient.sendBuildStateUpdate(buildState, + var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, currentThread.getName()); var thread = sentMessage.getThread(); var messageId = messageIdOf(sentMessage.getName()); @@ -76,4 +81,8 @@ Pair> on(@External BuildStateChanged e) } return Pair.withNullable(messageCreated, null); } + + void setGoogleChatClient(GoogleChatClient googleChatClient) { + this.googleChatClient = googleChatClient; + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java index a85fa4e3..e79b6311 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.api.GoogleChatClient; import io.spine.chatbot.github.repository.build.event.BuildStateChanged; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.thread.ThreadChat; @@ -33,6 +34,12 @@ final class ThreadChatProcessRepository extends ProcessManagerRepository { + private final GoogleChatClient googleChatClient; + + ThreadChatProcessRepository(GoogleChatClient googleChatClient) { + this.googleChatClient = googleChatClient; + } + @OverridingMethodsMustInvokeSuper @Override protected void setupEventRouting(EventRouting routing) { @@ -43,4 +50,9 @@ protected void setupEventRouting(EventRouting routing) { return withId(id); }); } + + @Override + protected void configure(ThreadChatProcess processManager) { + processManager.setGoogleChatClient(googleChatClient); + } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java new file mode 100644 index 00000000..207afce1 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java @@ -0,0 +1,74 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import io.spine.logging.Logging; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import static io.spine.util.Exceptions.newIllegalStateException; + +/** + * An abstract API client that exposes the {@code fail-fast} concept to the actual test clients. + */ +class FailFastClient implements Logging { + + /** Determines whether the client should fail if a particular response is not preconfigured. **/ + private final boolean failFast; + + /** Creates a new client with the specified {@code failFast} behavior. **/ + FailFastClient(boolean failFast) { + this.failFast = failFast; + } + + /** + * Applies the fail-fast approach to the supplied value if the client is configured so, + * otherwise returns the {@code defaultValue} if the supplied {@code value} is {@code null}. + * + * @param value + * the value under check + * @param key + * the key using which the {@code value} was obtained + * @param defaultValue + * the default value to be used if the client is not using the fail-fast approach and + * the value is {@code null} + * @param + * the type of the key the API client was called with + * @param + * the type of the value the API client is expected to return + * @throws IllegalStateException + * if the client is configured to use the fail-fast approach and the supplied + * {@code value} is {@code null} + */ + @NonNull V failOrDefault(@Nullable V value, @NonNull K key, @NonNull V defaultValue) { + if (failFast && value == null) { + throw newIllegalStateException( + "Response of type `%s` is not configured for the key `%s`.", + defaultValue.getClass() + .getSimpleName(), String.valueOf(key) + ); + } + if (!failFast && value == null) { + return defaultValue; + } + return value; + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java new file mode 100644 index 00000000..eff5f411 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java @@ -0,0 +1,74 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api; + +import com.google.api.services.chat.v1.model.Message; +import io.spine.chatbot.github.repository.build.BuildState; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An in-memory test-only implementation of the Google Chat client. + */ +public final class InMemoryGoogleChatClient extends FailFastClient implements GoogleChatClient { + + private final Map sentMessages = new ConcurrentHashMap<>(); + + private InMemoryGoogleChatClient(boolean failFast) { + super(failFast); + } + + /** Creates a {@link #failFast} in-memory Google Chat client. **/ + public static InMemoryGoogleChatClient strictClient() { + return new InMemoryGoogleChatClient(true); + } + + /** Creates a lenient in-memory Google Chat client. **/ + public static InMemoryGoogleChatClient lenientClient() { + return new InMemoryGoogleChatClient(false); + } + + @Override + public Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { + var stubbedValue = sentMessages.get(buildState.getNumber()); + var result = failOrDefault(stubbedValue, buildState.getNumber(), new Message()); + return result; + } + + /** + * Sets up a stub {@code message} for a build state update with the specified + * {@code buildNumber}. + */ + public void setMessageForBuildStatsUpdate(String buildNumber, Message message) { + checkNotNull(buildNumber); + checkNotNull(message); + sentMessages.put(buildNumber, message); + } + + /** Resets state of the configured responses. **/ + public void reset() { + sentMessages.clear(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java index b8c40831..eb1288ea 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java @@ -27,21 +27,17 @@ import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.util.Exceptions.newIllegalStateException; /** * An in-memory test-only implementation of the Travis CI API client. */ -public final class InMemoryTravisClient implements TravisClient { +public final class InMemoryTravisClient extends FailFastClient implements TravisClient { private final Map buildsResponses = new ConcurrentHashMap<>(); private final Map repositoriesResponses = new ConcurrentHashMap<>(); - /** Determines whether the client should fail if a particular response was not preconfigured. **/ - private final boolean failFast; - private InMemoryTravisClient(boolean failFast) { - this.failFast = failFast; + super(failFast); } /** Creates a {@link #failFast} in-memory Travis CI client. **/ @@ -57,41 +53,27 @@ public static InMemoryTravisClient lenientClient() { @Override public BuildsResponse queryBuildsFor(String repoSlug) { checkNotNull(repoSlug); - var result = buildsResponses.get(repoSlug); - if (failFast && result == null) { - throw newIllegalStateException( - "Builds response is not configured for the repository `%s`.", repoSlug - ); - } - if (!failFast && result == null) { - result = BuildsResponse.getDefaultInstance(); - } + var stubbedValue = buildsResponses.get(repoSlug); + var result = failOrDefault(stubbedValue, repoSlug, BuildsResponse.getDefaultInstance()); return result; } @Override public RepositoriesResponse queryRepositoriesFor(String owner) { checkNotNull(owner); - var result = repositoriesResponses.get(owner); - if (failFast && result == null) { - throw newIllegalStateException( - "Repositories response is not configured for the owner `%s`.", owner - ); - } - if (!failFast && result == null) { - result = RepositoriesResponse.getDefaultInstance(); - } + var stubbedValue = repositoriesResponses.get(owner); + var result = failOrDefault(stubbedValue, owner, RepositoriesResponse.getDefaultInstance()); return result; } - /** Sets up a mocked {@code builds} response for a specified {@code repoSlug}. **/ + /** Sets up a stub {@code builds} response for a specified {@code repoSlug}. **/ public void setBuildsFor(String repoSlug, BuildsResponse builds) { checkNotNull(repoSlug); checkNotNull(builds); buildsResponses.put(repoSlug, builds); } - /** Sets up a mocked {@code repositories} response for a specified {@code owner}. **/ + /** Sets up a stub {@code repositories} response for a specified {@code owner}. **/ public void setRepositoriesFor(String owner, RepositoriesResponse repositories) { checkNotNull(owner); checkNotNull(repositories); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java index db63be8f..0ff90c55 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -20,13 +20,34 @@ package io.spine.chatbot.server.google.chat; -import io.spine.testing.UtilityClassTest; +import io.spine.chatbot.api.InMemoryGoogleChatClient; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; @DisplayName("GoogleChatContext should") -final class GoogleChatContextTest extends UtilityClassTest { +final class GoogleChatContextTest { + + @Test + @DisplayName("allow configuring Google Chat client") + void allowConfiguringTravisClient() { + assertDoesNotThrow( + () -> GoogleChatContext + .newBuilder() + .setGoogleChatClient(InMemoryGoogleChatClient.lenientClient()) + .build() + ); + } - GoogleChatContextTest() { - super(GoogleChatContext.class); + @SuppressWarnings({"ResultOfMethodCallIgnored", "ConstantConditions"}) + @Test + @DisplayName("not allow passing `null` value as Google Chat client") + void notAllowNullTravisClients() { + assertThrows( + NullPointerException.class, () -> GoogleChatContext.newBuilder() + .setGoogleChatClient(null) + ); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java index ae86feff..09bf631b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java @@ -20,19 +20,29 @@ package io.spine.chatbot.server.google.chat; +import io.spine.chatbot.api.InMemoryGoogleChatClient; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; +import org.junit.jupiter.api.AfterEach; /** * An abstract test-base for Google Chat context tests. */ class GoogleChatTest extends ContextAwareTest { + final InMemoryGoogleChatClient googleChatClient = InMemoryGoogleChatClient.strictClient(); + @Override protected BoundedContextBuilder contextBuilder() { return GoogleChatContext .newBuilder() + .setGoogleChatClient(googleChatClient) .build() .contextBuilder(); } + + @AfterEach + void tearDown() { + googleChatClient.reset(); + } } From 20ce17f4536e24955b1321aa1fb73bfb3acf7b87 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 12:22:05 +0300 Subject: [PATCH 168/492] Rename abstract context tests --- .../server/github/{GitHubTest.java => GitHubEntityTest.java} | 4 ++-- .../chatbot/server/github/OrganizationAggregateTest.java | 2 +- .../chatbot/server/github/OrganizationInitProcessTest.java | 2 +- .../spine/chatbot/server/github/RepositoryAggregateTest.java | 2 +- .../chat/{GoogleChatTest.java => GoogleChatEntityTest.java} | 4 ++-- .../spine/chatbot/server/google/chat/SpaceAggregateTest.java | 2 +- .../spine/chatbot/server/google/chat/ThreadAggregateTest.java | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{GitHubTest.java => GitHubEntityTest.java} (94%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/{GoogleChatTest.java => GoogleChatEntityTest.java} (93%) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java similarity index 94% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java index 20443cb6..3935aa04 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java @@ -27,9 +27,9 @@ import org.junit.jupiter.api.AfterEach; /** - * An abstract test-base for GitHub context tests. + * An abstract test-base for GitHub context entity tests. */ -class GitHubTest extends ContextAwareTest { +class GitHubEntityTest extends ContextAwareTest { final InMemoryTravisClient travisClient = InMemoryTravisClient.strictClient(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 1def3de1..f85075cc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -34,7 +34,7 @@ import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") -final class OrganizationAggregateTest extends GitHubTest { +final class OrganizationAggregateTest extends GitHubEntityTest { @Nested @DisplayName("register an organization") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java index cb1d678f..d21a483d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java @@ -34,7 +34,7 @@ import static io.spine.chatbot.server.github.OrganizationInitProcess.SPINE_ORGANIZATION; @DisplayName("OrganizationInitProcess should") -final class OrganizationInitProcessTest extends GitHubTest { +final class OrganizationInitProcessTest extends GitHubEntityTest { @DisplayName("perform initialization of watched spine resources") @Nested diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 13120d5d..4277a89e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -36,7 +36,7 @@ import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") -final class RepositoryAggregateTest extends GitHubTest { +final class RepositoryAggregateTest extends GitHubEntityTest { @Nested @DisplayName("register a repository") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java similarity index 93% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java index 09bf631b..8c4d7b12 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java @@ -26,9 +26,9 @@ import org.junit.jupiter.api.AfterEach; /** - * An abstract test-base for Google Chat context tests. + * An abstract test-base for Google Chat context entity tests. */ -class GoogleChatTest extends ContextAwareTest { +class GoogleChatEntityTest extends ContextAwareTest { final InMemoryGoogleChatClient googleChatClient = InMemoryGoogleChatClient.strictClient(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 12c3a318..d12613aa 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -30,7 +30,7 @@ import org.junit.jupiter.api.Test; @DisplayName("SpaceAggregate should") -final class SpaceAggregateTest extends GoogleChatTest { +final class SpaceAggregateTest extends GoogleChatEntityTest { @Nested @DisplayName("register a space") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 5bbc2194..d09f629f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -40,7 +40,7 @@ import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") -final class ThreadAggregateTest extends GoogleChatTest { +final class ThreadAggregateTest extends GoogleChatEntityTest { @Nested @DisplayName("initialize a thread") From 225a3ab6bae373c03c8c38e915733ed942f3ca7d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 12:30:53 +0300 Subject: [PATCH 169/492] Add logs --- .../main/java/io/spine/chatbot/api/GoogleChat.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java index 40806d7c..89a4f8c2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java @@ -28,6 +28,7 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.logging.Logging; import javax.annotation.Nullable; import java.io.IOException; @@ -40,7 +41,7 @@ * * @see Hangouts Chat API */ -public final class GoogleChat implements GoogleChatClient { +public final class GoogleChat implements GoogleChatClient, Logging { private static final String BOT_NAME = "Spine Chat Bot"; private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; @@ -60,8 +61,16 @@ public static GoogleChatClient defaultGoogleChatClient() { @Override public Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { + var repoSlug = buildState.getRepositorySlug(); + _debug().log("Sending build state update message for repository `%s`.", repoSlug); var message = buildStateMessage(buildState, threadName); - return sendMessage(buildState.getGoogleChatSpace(), message); + var result = sendMessage(buildState.getGoogleChatSpace(), message); + _debug().log( + "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", + result.getName(), repoSlug, result.getThread() + .getName() + ); + return result; } @CanIgnoreReturnValue From a3aea6927edb0b0e54ef46e8b86a404c0f8d1615 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 17:47:43 +0300 Subject: [PATCH 170/492] Rework the way we work with the build state changes. Introduce more precise build state events. Handle different build state changes flows. --- .../spine/chatbot/api/BuildStateUpdates.java | 7 +- .../chatbot/server/github/BuildStates.java | 50 +++++++++++ .../server/github/RepositoryAware.java | 34 ++++++++ .../server/github/RepositoryAwareEvent.java | 42 ++++++++++ .../server/github/RepositoryBuildProcess.java | 82 +++++++++++++++++-- .../server/google/chat/ThreadChatProcess.java | 48 ++++++++--- .../chat/ThreadChatProcessRepository.java | 26 ++++-- .../chatbot/github/repository_build.proto | 51 +++++++++++- .../github/repository_build_events.proto | 31 ++++++- 9 files changed, 341 insertions(+), 30 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java index 13b2fcc5..168244eb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java @@ -101,7 +101,12 @@ private static WidgetMarkup buildStateWidget(BuildState buildState) { var keyValue = new KeyValue() .setTopLabel("Build No.") .setContent(buildState.getNumber()) - .setBottomLabel(buildState.getState()); + .setBottomLabel(capitalizeState(buildState.getState())); return new WidgetMarkup().setKeyValue(keyValue); } + + private static String capitalizeState(BuildState.State state) { + var name = state.name(); + return name.charAt(0) + name.toLowerCase(); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java new file mode 100644 index 00000000..6f3580f6 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java @@ -0,0 +1,50 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.repository.build.BuildState; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Exceptions.newIllegalArgumentException; + +/** + * A utility class for working with {@link io.spine.chatbot.github.repository.build.BuildState.State + * BuildState.State}s. + */ +public final class BuildStates { + + /** Prevents instantiation of this utility class. **/ + private BuildStates() { + } + + /** Creates an instance of the build state of out its string representation. */ + public static BuildState.State buildStateFrom(String state) { + checkNotNull(state); + for (BuildState.State buildState : BuildState.State.values()) { + if (state.equalsIgnoreCase(buildState.name())) { + return buildState; + } + } + throw newIllegalArgumentException( + "Unable to create build state out of the supplied string value `%s`.", state + ); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java new file mode 100644 index 00000000..cdea683d --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.RepositoryId; + +/** + * Common interface for messages aware of the {@link RepositoryId repository}. + */ +public interface RepositoryAware { + + /** + * Obtains the repository ID. + */ + RepositoryId getId(); +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java new file mode 100644 index 00000000..5836d556 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import com.google.errorprone.annotations.Immutable; +import io.spine.annotation.GeneratedMixin; +import io.spine.base.EventMessage; +import io.spine.chatbot.github.RepositoryId; + +import java.util.Set; + +import static io.spine.server.route.EventRoute.withId; + +/** + * A repository-aware event message. + */ +@GeneratedMixin +@Immutable +public interface RepositoryAwareEvent extends RepositoryAware, EventMessage { + + default Set repository() { + return withId(getId()); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index 7ae0a4ae..660d7b91 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -20,32 +20,47 @@ package io.spine.chatbot.server.github; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; import io.spine.chatbot.api.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; +import io.spine.chatbot.github.repository.build.BuildStateStatusChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; -import io.spine.chatbot.github.repository.build.event.BuildStateChanged; +import io.spine.chatbot.github.repository.build.event.BuildFailed; +import io.spine.chatbot.github.repository.build.event.BuildRecovered; +import io.spine.chatbot.github.repository.build.event.BuildStable; import io.spine.chatbot.travis.Build; import io.spine.chatbot.travis.Commit; import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; +import io.spine.server.tuple.EitherOf3; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import static io.spine.chatbot.github.repository.build.BuildState.State.PASSED; +import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.FAILED; +import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; +import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; +import static io.spine.chatbot.server.github.BuildStates.buildStateFrom; import static io.spine.net.Urls.travisBuildUrlFor; +import static io.spine.util.Exceptions.newIllegalStateException; final class RepositoryBuildProcess extends ProcessManager { + private static final ImmutableSet FAILED_STATUSES = ImmutableSet.of( + BuildState.State.CANCELLED, BuildState.State.FAILED, BuildState.State.ERRORED + ); + @LazyInit private @MonotonicNonNull TravisClient travisClient; @Assign - BuildStateChanged handle(CheckRepositoryBuild c) { + EitherOf3 handle(CheckRepositoryBuild c) { var builds = travisClient.queryBuildsFor(id().getValue()) .getBuildsList(); if (builds.isEmpty()) { @@ -60,11 +75,60 @@ BuildStateChanged handle(CheckRepositoryBuild c) { .setPreviousValue(state().getBuildState()) .setNewValue(buildState) .vBuild(); - return BuildStateChanged - .newBuilder() - .setId(c.getId()) - .setChange(stateChange) - .vBuild(); + var result = determineOutcome(c.getId(), stateChange); + return result; + } + + private static EitherOf3 + determineOutcome(RepositoryId id, BuildStateChange stateChange) { + var stateStatusChange = stateStatusChangeOf(stateChange.getNewValue()); + switch (stateStatusChange) { + case FAILED: + var buildFailed = BuildFailed + .newBuilder() + .setId(id) + .setChange(stateChange) + .vBuild(); + return EitherOf3.withA(buildFailed); + case RECOVERED: + var buildRecovered = BuildRecovered + .newBuilder() + .setId(id) + .setChange(stateChange) + .vBuild(); + return EitherOf3.withB(buildRecovered); + case STABLE: + var buildStable = BuildStable + .newBuilder() + .setId(id) + .setChange(stateChange) + .vBuild(); + return EitherOf3.withC(buildStable); + case BSC_UNKNOWN: + case UNRECOGNIZED: + default: + throw newIllegalStateException( + "Unexpected state status change `%s`.", stateStatusChange + ); + } + } + + private static BuildStateStatusChange stateStatusChangeOf(BuildState buildState) { + var currentState = buildState.getState(); + var previousState = buildState.getPreviousState(); + if (FAILED_STATUSES.contains(currentState)) { + return FAILED; + } + if (currentState == PASSED && FAILED_STATUSES.contains(previousState)) { + return RECOVERED; + } + if (currentState == PASSED && previousState == PASSED) { + return STABLE; + } + throw newIllegalStateException( + "Build is in an unpredictable state. Current state `%s`. Previous state `%s`.", + currentState.name(), previousState.name() + ); } private static BuildState from(Build build) { @@ -72,8 +136,8 @@ private static BuildState from(Build build) { .getSlug(); return BuildState .newBuilder() - .setState(build.getState()) - .setPreviousState(build.getPreviousState()) + .setState(buildStateFrom(build.getState())) + .setPreviousState(buildStateFrom(build.getPreviousState())) .setBranch(build.getBranch() .getName()) .setLastCommit(from(build.getCommit())) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 34e7e337..9fc44719 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -23,7 +23,10 @@ import com.google.common.base.Strings; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.chatbot.api.GoogleChatClient; -import io.spine.chatbot.github.repository.build.event.BuildStateChanged; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.event.BuildFailed; +import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.event.MessageCreated; import io.spine.chatbot.google.chat.event.ThreadCreated; @@ -49,26 +52,42 @@ final class ThreadChatProcess extends ProcessManager> on(@External BuildStateChanged e) { + Pair> on(@External BuildFailed e) { var change = e.getChange(); var buildState = change.getNewValue(); var repositoryId = e.getId(); + _info().log("Build for repository `%s` failed.", repositoryId.getValue()); + + return processBuildStateUpdate(buildState, repositoryId); + } + + @React + Pair> on(@External BuildRecovered e) { + var change = e.getChange(); + var buildState = change.getNewValue(); + var repositoryId = e.getId(); + _info().log("Build for repository `%s` recovered.", repositoryId.getValue()); + + return processBuildStateUpdate(buildState, repositoryId); + } + + private Pair> processBuildStateUpdate( + BuildState buildState, RepositoryId repositoryId) { + var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, currentThreadName()); + var messageId = messageIdOf(sentMessage.getName()); var threadId = threadIdOf(repositoryId.getValue()); var spaceId = spaceIdOf(buildState.getGoogleChatSpace()); - var currentThread = state().getThread(); - _info().log("Build state changed for the repository `%s`.", repositoryId.getValue()); - var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, - currentThread.getName()); - var thread = sentMessage.getThread(); - var messageId = messageIdOf(sentMessage.getName()); var messageCreated = MessageCreated .newBuilder() .setId(messageId) .setSpaceId(spaceId) .setThreadId(threadId) .vBuild(); - if (Strings.isNullOrEmpty(currentThread.getName())) { - var newThread = threadResourceOf(thread.getName()); + if (shouldCreateThread()) { + var newThread = threadResourceOf(sentMessage.getThread() + .getName()); + _debug().log("New thread `%s` created for repository `%s`.", + newThread.getName(), repositoryId.getValue()); builder().setThread(newThread) .setSpaceId(spaceId); var threadCreated = ThreadCreated @@ -82,6 +101,15 @@ Pair> on(@External BuildStateChanged e) return Pair.withNullable(messageCreated, null); } + private boolean shouldCreateThread() { + return Strings.isNullOrEmpty(currentThreadName()); + } + + private String currentThreadName() { + return state().getThread() + .getName(); + } + void setGoogleChatClient(GoogleChatClient googleChatClient) { this.googleChatClient = googleChatClient; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java index e79b6311..61869ed6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -22,12 +22,18 @@ import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.chatbot.api.GoogleChatClient; -import io.spine.chatbot.github.repository.build.event.BuildStateChanged; +import io.spine.chatbot.github.repository.build.event.BuildFailed; +import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.thread.ThreadChat; +import io.spine.chatbot.server.github.RepositoryAwareEvent; +import io.spine.core.EventContext; import io.spine.server.procman.ProcessManagerRepository; +import io.spine.server.route.EventRoute; import io.spine.server.route.EventRouting; +import java.util.Set; + import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; import static io.spine.server.route.EventRoute.withId; @@ -44,15 +50,23 @@ final class ThreadChatProcessRepository @Override protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); - routing.route(BuildStateChanged.class, (event, context) -> { - var repositoryId = event.getId(); - var id = threadIdOf(repositoryId.getValue()); - return withId(id); - }); + routing.route(BuildFailed.class, new RepositoryEventRoute<>()); + routing.route(BuildRecovered.class, new RepositoryEventRoute<>()); } @Override protected void configure(ThreadChatProcess processManager) { processManager.setGoogleChatClient(googleChatClient); } + + private static class RepositoryEventRoute implements EventRoute { + + private static final long serialVersionUID = 5147803958347083018L; + + @Override + public Set apply(M event, EventContext context) { + var repositoryId = event.getId(); + return withId(threadIdOf(repositoryId.getValue())); + } + } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 8d2de708..505ce904 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -50,6 +50,23 @@ message RepositoryBuild { BuildState build_state = 3; } +// The state change status of the build. +enum BuildStateStatusChange { + + BSC_UNKNOWN = 0; + + // The build has failed. + // + // It could be either a build configuration failure or the actual code build issue. + FAILED = 1; + + // The build has recovered from the failed state. + RECOVERED = 2; + + // The build is stable. + STABLE = 3; +} + // State of the build for a repository branch. message BuildState { @@ -60,10 +77,40 @@ message BuildState { spine.net.Url travis_ci_url = 2; // Current state of the build. - string state = 3; + State state = 3; // State of the previous build. - string previous_state = 4; + State previous_state = 4; + + // The build state. + enum State { + S_UNKNOWN = 0; + + // The build is created. + CREATED = 1; + + // The build is received by the CI. + RECEIVED = 2; + + // The build is in progress. + STARTED = 3; + + // The build has passed successfully. + PASSED = 4; + + // The build has failed. + // + // Denotes that the developer code could not be successfully built. + FAILED = 5; + + // The build configuration has failed. + // + // Denotes that the build configuration or pre-build steps failed. + ERRORED = 6; + + // The build is cancelled. + CANCELLED = 7; + } // The branch the build is associated with. string branch = 5; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 96c651d4..97737e02 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -29,14 +29,41 @@ option java_package = "io.spine.chatbot.github.repository.build.event"; option java_outer_classname = "RepositoryBuildEventsProto"; option java_multiple_files = true; +option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; + import "spine/chatbot/github/identifiers.proto"; import "spine/chatbot/github/repository_build.proto"; -// Denotes that a build state was changed. -message BuildStateChanged { +// The build has failed for a repository. +message BuildFailed { + + RepositoryId id = 1 [(required) = true]; + + // The change of the build state. + BuildStateChange change = 2; +} + +// The build has recovered from the failed state. +message BuildRecovered { + + RepositoryId id = 1 [(required) = true]; + + // The change of the build state. + BuildStateChange change = 2; +} + +// The build is stable and passing. +message BuildStable { RepositoryId id = 1 [(required) = true]; + // The change of the build state. BuildStateChange change = 2; } + +// The build is stable and passing. +message BuildInProgress { + + RepositoryId id = 1 [(required) = true]; +} \ No newline at end of file From 2ad1c3932f8601f40b0014a1024e520fc8dd9e66 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 18:10:40 +0300 Subject: [PATCH 171/492] Add ThreadChatProcess integration tests --- .../server/google/chat/ThreadChatProcess.java | 4 +- .../chatbot/api/InMemoryGoogleChatClient.java | 2 +- .../google/chat/ThreadChatProcessTest.java | 143 ++++++++++++++++++ 3 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 9fc44719..365b6d43 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -71,8 +71,8 @@ Pair> on(@External BuildRecovered e) { return processBuildStateUpdate(buildState, repositoryId); } - private Pair> processBuildStateUpdate( - BuildState buildState, RepositoryId repositoryId) { + private Pair> + processBuildStateUpdate(BuildState buildState, RepositoryId repositoryId) { var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, currentThreadName()); var messageId = messageIdOf(sentMessage.getName()); var threadId = threadIdOf(repositoryId.getValue()); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java index eff5f411..ee0444bf 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java @@ -61,7 +61,7 @@ public Message sendBuildStateUpdate(BuildState buildState, @Nullable String thre * Sets up a stub {@code message} for a build state update with the specified * {@code buildNumber}. */ - public void setMessageForBuildStatsUpdate(String buildNumber, Message message) { + public void setMessageForBuildStatusUpdate(String buildNumber, Message message) { checkNotNull(buildNumber); checkNotNull(message); sentMessages.put(buildNumber, message); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java new file mode 100644 index 00000000..4702228f --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import com.google.api.services.chat.v1.model.Message; +import com.google.api.services.chat.v1.model.Thread; +import io.spine.base.EventMessage; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.BuildStateChange; +import io.spine.chatbot.github.repository.build.event.BuildFailed; +import io.spine.chatbot.github.repository.build.event.BuildRecovered; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.ThreadId; +import io.spine.chatbot.google.chat.event.MessageCreated; +import io.spine.chatbot.google.chat.event.ThreadCreated; +import io.spine.chatbot.google.chat.thread.ThreadChat; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; + +@DisplayName("ThreadChatProcess should") +final class ThreadChatProcessTest { + + @Nested + @DisplayName("sent a message to the Google Chat room when build failed") + final class BuildIsFailed extends BuildStateChanged { + + @Override + EventMessage buildStateChangeEvent(RepositoryId repositoryId, + BuildStateChange stateChange) { + return BuildFailed + .newBuilder() + .setId(repositoryId) + .setChange(stateChange) + .vBuild(); + } + } + + @Nested + @DisplayName("sent a message to the Google Chat room when build recovered from failure") + final class BuildIsRecovered extends BuildStateChanged { + + @Override + EventMessage buildStateChangeEvent(RepositoryId repositoryId, + BuildStateChange stateChange) { + return BuildRecovered + .newBuilder() + .setId(repositoryId) + .setChange(stateChange) + .vBuild(); + } + } + + private abstract static class BuildStateChanged extends GoogleChatEntityTest { + + private final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/money"); + private final ThreadId threadId = threadIdOf(repositoryId.getValue()); + private final String googleChatSpace = "spaces/1241pjwqe"; + private final SpaceId spaceId = spaceIdOf(googleChatSpace); + private final String buildNumber = "551"; + private final Thread newThread = new Thread().setName("spaces/1241pjwqe/thread/k12d1o2r1"); + private final Message sentMessage = new Message() + .setName("spaces/1241pjwqe/messages/12154363643624") + .setThread(newThread); + + @BeforeEach + void setUp() { + googleChatClient.setMessageForBuildStatusUpdate(buildNumber, sentMessage); + var newBuildState = BuildState + .newBuilder() + .setGoogleChatSpace(googleChatSpace) + .setNumber(buildNumber) + .vBuild(); + var buildStateChange = BuildStateChange + .newBuilder() + .setNewValue(newBuildState) + .vBuild(); + var buildFailed = buildStateChangeEvent(repositoryId, buildStateChange); + context().receivesExternalEvent(buildFailed); + } + + abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, + BuildStateChange stateChange); + + @Test + @DisplayName("producing MessageCreated and ThreadCreated events") + void producingEvent() { + var messageCreated = MessageCreated + .newBuilder() + .setId(messageIdOf(sentMessage.getName())) + .setThreadId(threadId) + .setSpaceId(spaceId) + .vBuild(); + var threadCreated = ThreadCreated + .newBuilder() + .setId(threadId) + .setThread(threadResourceOf(newThread.getName())) + .setSpaceId(spaceId) + .vBuild(); + context().assertEvent(messageCreated); + context().assertEvent(threadCreated); + } + + @Test + @DisplayName("setting process state") + void settingState() { + var expectedState = ThreadChat + .newBuilder() + .setId(threadId) + .setSpaceId(spaceId) + .setThread(threadResourceOf(newThread.getName())) + .vBuild(); + context().assertState(threadId, ThreadChat.class) + .isEqualTo(expectedState); + } + } +} From dea825527c6b6ff5b4c8648966c11c3bdec7dcfc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 18:53:44 +0300 Subject: [PATCH 172/492] Enable `equals` and `hashCode` generation --- .../src/main/proto/spine/chatbot/github/identifiers.proto | 1 + .../src/main/proto/spine/chatbot/github/organization.proto | 1 + .../main/proto/spine/chatbot/github/organization_commands.proto | 1 + .../main/proto/spine/chatbot/github/organization_events.proto | 1 + .../src/main/proto/spine/chatbot/github/organization_init.proto | 1 + .../proto/spine/chatbot/github/organization_init_commands.proto | 1 + .../proto/spine/chatbot/github/organization_repositories.proto | 1 + .../src/main/proto/spine/chatbot/github/repository.proto | 1 + .../src/main/proto/spine/chatbot/github/repository_build.proto | 1 + .../proto/spine/chatbot/github/repository_build_commands.proto | 1 + .../proto/spine/chatbot/github/repository_build_events.proto | 1 + .../main/proto/spine/chatbot/github/repository_commands.proto | 1 + .../src/main/proto/spine/chatbot/github/repository_events.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/chat_events.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/identifiers.proto | 1 + .../chatbot/google/chat/incoming/incoming_chat_messages.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/space.proto | 1 + .../main/proto/spine/chatbot/google/chat/space_commands.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/space_events.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/thread.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/thread_chat.proto | 1 + .../src/main/proto/spine/chatbot/google/chat/thread_events.proto | 1 + google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto | 1 + 23 files changed, 23 insertions(+) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index 8b57d702..5c2722fe 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github"; option java_outer_classname = "IdentifiersProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; // GitHub organization ID. message OrganizationId { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index ed6cd6b7..c847ece0 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization"; option java_outer_classname = "OrganizationProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/net/url.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 657c83ec..dfb7254a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.command"; option java_outer_classname = "OrganizationCommandsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/net/url.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index 570b87b4..773e71d1 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.event"; option java_outer_classname = "OrganizationEventsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/net/url.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index a0fe604a..4f019582 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.init"; option java_outer_classname = "OrganizationInitProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index 74beecf3..0a1a259a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.init.command"; option java_outer_classname = "OrganizationInitCommandsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index ef912fb7..6bfd28fd 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization"; option java_outer_classname = "OrganizationRepositoriesProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 801cbfef..a8dec37e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.repository"; option java_outer_classname = "RepositoryProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/net/url.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 505ce904..ea7c1fb2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.repository.build"; option java_outer_classname = "RepositoryBuildProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "google/protobuf/timestamp.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 201c3b00..27472e77 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.repository.build.command"; option java_outer_classname = "RepositoryBuildCommandsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 97737e02..3de245ef 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.repository.build.event"; option java_outer_classname = "RepositoryBuildEventsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 2339b7ba..e19c4262 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.repository.command"; option java_outer_classname = "RepositoryCommandsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/net/url.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index ed1890fc..912024f0 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.repository.event"; option java_outer_classname = "RepositoryEventsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/net/url.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index 4a6e68a8..779bbf96 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.event"; option java_outer_classname = "ChatEventsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto index 70a408c3..6028e329 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat"; option java_outer_classname = "IdentifiersProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; // Hangouts Chat Space identifier. message SpaceId { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index b3c7a353..ea47a302 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.incoming"; option java_outer_classname = "IncomingChatMessagesProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; // Denotes that a message was created in the space. message ChatEvent { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index e84752e4..f41f0a8b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat"; option java_outer_classname = "SpaceProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 48a5400c..89e56ae1 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.command"; option java_outer_classname = "SpaceCommandsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto index 4fbfc09a..2159aac2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.event"; option java_outer_classname = "SpaceEventsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index f57a9ff6..e10ee707 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.thread"; option java_outer_classname = "ThreadProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto index 6de7fb6f..6f2f2006 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.thread"; option java_outer_classname = "ThreadChatProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index 5293e392..2e660f34 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.google.chat.thread.event"; option java_outer_classname = "ThreadEventsProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 3f08ae0a..60dfe38e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -28,6 +28,7 @@ option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.travis"; option java_outer_classname = "TravisCiProto"; option java_multiple_files = true; +option java_generate_equals_and_hash = true; message Owner { From fe460fe145479cbe4ac33cff5d653a515d04ca42 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 18:54:09 +0300 Subject: [PATCH 173/492] Cleanup --- .../spine/chatbot/server/github/RepositoryBuildProcess.java | 4 +++- .../chatbot/server/github/OrganizationInitProcessTest.java | 4 ++-- .../chatbot/server/google/chat/GoogleChatEntityTest.java | 6 +++++- .../chatbot/server/google/chat/ThreadChatProcessTest.java | 2 ++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index 660d7b91..149a1bf9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -64,7 +64,9 @@ EitherOf3 handle(CheckRepositoryBuild var builds = travisClient.queryBuildsFor(id().getValue()) .getBuildsList(); if (builds.isEmpty()) { - throw new RuntimeException("No builds available for repository " + idAsString()); + throw newIllegalStateException( + "No build found for the repository `%s`.", id().getValue() + ); } var build = builds.get(0); var buildState = from(build); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java index d21a483d..861656d4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java @@ -36,9 +36,9 @@ @DisplayName("OrganizationInitProcess should") final class OrganizationInitProcessTest extends GitHubEntityTest { - @DisplayName("perform initialization of watched spine resources") @Nested - class Init { + @DisplayName("perform initialization of watched spine resources") + final class Init { private final SpaceId spaceId = Identifiers.spaceIdOf("spaces/qjwrp1441"); private final Repository repository = Repository diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java index 8c4d7b12..509d1a94 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.google.chat; +import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; import io.spine.chatbot.api.InMemoryGoogleChatClient; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; @@ -42,7 +43,10 @@ protected BoundedContextBuilder contextBuilder() { } @AfterEach - void tearDown() { + @OverridingMethodsMustInvokeSuper + @Override + protected void closeContext() { + super.closeContext(); googleChatClient.reset(); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 4702228f..22f96600 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -47,6 +47,7 @@ @DisplayName("ThreadChatProcess should") final class ThreadChatProcessTest { + @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes @Nested @DisplayName("sent a message to the Google Chat room when build failed") final class BuildIsFailed extends BuildStateChanged { @@ -62,6 +63,7 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, } } + @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes @Nested @DisplayName("sent a message to the Google Chat room when build recovered from failure") final class BuildIsRecovered extends BuildStateChanged { From 9c53d2345064e4e5508d61e9a15b022e264ad92c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 18:55:32 +0300 Subject: [PATCH 174/492] Add TODO about RuntimeException usage --- .../io/spine/chatbot/server/github/RepositoryBuildProcess.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index 149a1bf9..a413f665 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -64,6 +64,8 @@ EitherOf3 handle(CheckRepositoryBuild var builds = travisClient.queryBuildsFor(id().getValue()) .getBuildsList(); if (builds.isEmpty()) { + //TODO:2020-06-19:yuri-sergiichuk: replace with `NoBuildsFound` rejection after migration + // to the new java11-compatible Bootstrap version throw newIllegalStateException( "No build found for the repository `%s`.", id().getValue() ); From 78ea410987e3444bded151cf91b45c58af7e2f6f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 18:56:18 +0300 Subject: [PATCH 175/492] Add repo build rejections --- .../github/repository_build_rejections.proto1 | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 new file mode 100644 index 00000000..34b100d7 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 @@ -0,0 +1,44 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github.repository.build.rejection"; +option java_multiple_files = false; +option java_generate_equals_and_hash = true; + +option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; + + +import "spine/chatbot/github/identifiers.proto"; + +//TODO:2020-06-19:yuri-sergiichuk: rename file back to `.proto` after migration +// to the new java11-compatible Bootstrap version + +// No CI builds found for the repository. +message NoBuildsFound { + + RepositoryId id = 1 [(required) = true]; +} From 3c8f67c274ad71c46b2b971de8365718f1b227b4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 18:56:39 +0300 Subject: [PATCH 176/492] Mark `@Test` as jUnit jupiter entry point --- .idea/misc.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 05eabd13..576b6cbd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,12 +1,13 @@ - + + From e5d03a0e0d9a9a2cbf85d8c04bc683c199ae5bbc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 19:18:46 +0300 Subject: [PATCH 177/492] Add FailedBuild handling test case --- .../server/github/RepositoryBuildProcess.java | 11 +- .../github/RepositoryBuildProcessTest.java | 140 ++++++++++++++++++ .../google/chat/ThreadChatProcessTest.java | 2 +- 3 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index a413f665..0563a79c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.github; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; @@ -45,7 +46,6 @@ import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.FAILED; import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; -import static io.spine.chatbot.server.github.BuildStates.buildStateFrom; import static io.spine.net.Urls.travisBuildUrlFor; import static io.spine.util.Exceptions.newIllegalStateException; @@ -71,7 +71,7 @@ EitherOf3 handle(CheckRepositoryBuild ); } var build = builds.get(0); - var buildState = from(build); + var buildState = buildStateFrom(build); builder().setLastStatusCheck(Time.currentTime()) .setBuildState(buildState); var stateChange = BuildStateChange @@ -135,13 +135,14 @@ private static BuildStateStatusChange stateStatusChangeOf(BuildState buildState) ); } - private static BuildState from(Build build) { + @VisibleForTesting + static BuildState buildStateFrom(Build build) { var slug = build.getRepository() .getSlug(); return BuildState .newBuilder() - .setState(buildStateFrom(build.getState())) - .setPreviousState(buildStateFrom(build.getPreviousState())) + .setState(BuildStates.buildStateFrom(build.getState())) + .setPreviousState(BuildStates.buildStateFrom(build.getPreviousState())) .setBranch(build.getBranch() .getName()) .setLastCommit(from(build.getCommit())) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java new file mode 100644 index 00000000..5f0c3e44 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java @@ -0,0 +1,140 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.BuildStateChange; +import io.spine.chatbot.github.repository.build.RepositoryBuild; +import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; +import io.spine.chatbot.github.repository.build.event.BuildFailed; +import io.spine.chatbot.travis.Build; +import io.spine.chatbot.travis.BuildsResponse; +import io.spine.chatbot.travis.Commit; +import io.spine.chatbot.travis.Repository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.chatbot.server.github.RepositoryBuildProcess.buildStateFrom; + +@DisplayName("RepositoryBuildProcess should") +final class RepositoryBuildProcessTest extends GitHubEntityTest { + + private static final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/web"); + + @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes + @Nested + @DisplayName("handle ") + final class FailedBuild { + + private final Build build = failedBuild(); + private final BuildState buildState = buildStateFrom(build); + + @BeforeEach + void setUp() { + travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(build)); + var checkRepoBuild = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().receivesCommand(checkRepoBuild); + } + + @Test + @DisplayName("producing MessageCreated and ThreadCreated events") + void producingEvents() { + var stateChange = BuildStateChange + .newBuilder() + .setNewValue(buildState) + .vBuild(); + var buildFailed = BuildFailed + .newBuilder() + .setId(repositoryId) + .setChange(stateChange) + .vBuild(); + context().assertEvent(buildFailed); + } + + @Test + @DisplayName("setting process state") + void settingState() { + var expectedState = RepositoryBuild + .newBuilder() + .setId(repositoryId) + .setBuildState(buildState) + .vBuild(); + context().assertState(repositoryId, RepositoryBuild.class) + .isEqualTo(expectedState); + } + } + + private static BuildsResponse singleBuild(Build build) { + return BuildsResponse + .newBuilder() + .addBuilds(build) + .buildPartial(); + } + + private static Build failedBuild() { + return buildWithState("failed", "failed"); + } + + private static Build buildWithState(String state, String previousState) { + return Build + .newBuilder() + .setId(123152L) + .setNumber("42") + .setState(state) + .setPreviousState(previousState) + .setRepository(webRepository()) + .setCommit(fatefulCommit()) + .buildPartial(); + } + + private static Commit fatefulCommit() { + var compareUrl = "https://github.com/SpineEventEngine/web/compare/5cbfa7423708...8fcf5d98e50f"; + var author = Commit.Author + .newBuilder() + .setName("Lucifer") + .buildPartial(); + return Commit + .newBuilder() + .setId(666) + .setCompareUrl(compareUrl) + .setSha("8fcf5d98e50f8ffa6daa8c81746181c72bd09a50") + .setAuthor(author) + .setCommittedAt("2020-06-06T06:06:66Z") + .setMessage("I am going to conquer the world!") + .buildPartial(); + + } + + private static Repository webRepository() { + return Repository.newBuilder() + .setId(1112) + .setName("web") + .setSlug(repositoryId.getValue()) + .buildPartial(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 22f96600..3e76243e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -112,7 +112,7 @@ abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, @Test @DisplayName("producing MessageCreated and ThreadCreated events") - void producingEvent() { + void producingEvents() { var messageCreated = MessageCreated .newBuilder() .setId(messageIdOf(sentMessage.getName())) From 2d2af07726ed8dffe3d032dce2af1db7bfaf67ad Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 19:30:20 +0300 Subject: [PATCH 178/492] Add BuildRecovered handling test case --- .../github/RepositoryBuildProcessTest.java | 103 ++++++++++++++++-- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java index 5f0c3e44..83658caf 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java @@ -26,6 +26,7 @@ import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.chatbot.github.repository.build.event.BuildFailed; +import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.travis.Build; import io.spine.chatbot.travis.BuildsResponse; import io.spine.chatbot.travis.Commit; @@ -45,7 +46,7 @@ final class RepositoryBuildProcessTest extends GitHubEntityTest { @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes @Nested - @DisplayName("handle ") + @DisplayName("handle build failure") final class FailedBuild { private final Build build = failedBuild(); @@ -62,8 +63,8 @@ void setUp() { } @Test - @DisplayName("producing MessageCreated and ThreadCreated events") - void producingEvents() { + @DisplayName("producing BuildFailed event") + void producingEvent() { var stateChange = BuildStateChange .newBuilder() .setNewValue(buildState) @@ -89,6 +90,62 @@ void settingState() { } } + @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes + @Nested + @DisplayName("handle build recovery") + final class RecoveredBuild { + + private final Build previousBuild = failedBuild(); + private final BuildState previousBuildState = buildStateFrom(previousBuild); + + private final Build newBuild = passingBuild(); + private final BuildState newBuildState = buildStateFrom(newBuild); + + @BeforeEach + void setUp() { + travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); + var checkRepoFailure = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().receivesCommand(checkRepoFailure); + travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); + var checkRepoRecovery = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().receivesCommand(checkRepoRecovery); + } + + @Test + @DisplayName("producing BuildRecovered event") + void producingEvent() { + var stateChange = BuildStateChange + .newBuilder() + .setPreviousValue(previousBuildState) + .setNewValue(newBuildState) + .vBuild(); + var buildFailed = BuildRecovered + .newBuilder() + .setId(repositoryId) + .setChange(stateChange) + .vBuild(); + context().assertEvent(buildFailed); + } + + @Test + @DisplayName("setting process state") + void settingState() { + var expectedState = RepositoryBuild + .newBuilder() + .setId(repositoryId) + .setBuildState(newBuildState) + .vBuild(); + context().assertState(repositoryId, RepositoryBuild.class) + .isEqualTo(expectedState); + } + } + private static BuildsResponse singleBuild(Build build) { return BuildsResponse .newBuilder() @@ -96,20 +153,46 @@ private static BuildsResponse singleBuild(Build build) { .buildPartial(); } - private static Build failedBuild() { - return buildWithState("failed", "failed"); + private static Build passingBuild() { + return Build + .newBuilder() + .setId(123153L) + .setNumber("42") + .setState("passed") + .setPreviousState("failed") + .setRepository(webRepository()) + .setCommit(luckyCommit()) + .buildPartial(); } - private static Build buildWithState(String state, String previousState) { + private static Build failedBuild() { return Build .newBuilder() .setId(123152L) - .setNumber("42") - .setState(state) - .setPreviousState(previousState) + .setNumber("41") + .setState("failed") + .setPreviousState("failed") .setRepository(webRepository()) - .setCommit(fatefulCommit()) + .setCommit(luckyCommit()) + .buildPartial(); + } + + private static Commit luckyCommit() { + var compareUrl = "https://github.com/SpineEventEngine/web/compare/6b4d32cadd9c...6b0a31d033a2"; + var author = Commit.Author + .newBuilder() + .setName("God") .buildPartial(); + return Commit + .newBuilder() + .setId(667) + .setCompareUrl(compareUrl) + .setSha("6b0a31d033a2fc8d29d49baad600bc31789d9615") + .setAuthor(author) + .setCommittedAt("2020-06-06T18:00:00Z") + .setMessage("No you're not. Fixing the world.") + .buildPartial(); + } private static Commit fatefulCommit() { From c089683b141cb17c54a461821eb62d47d4a35158 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 19:35:27 +0300 Subject: [PATCH 179/492] Add BuildStable handling test case --- .../github/RepositoryBuildProcessTest.java | 89 ++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java index 83658caf..93bec465 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java @@ -27,6 +27,7 @@ import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; +import io.spine.chatbot.github.repository.build.event.BuildStable; import io.spine.chatbot.travis.Build; import io.spine.chatbot.travis.BuildsResponse; import io.spine.chatbot.travis.Commit; @@ -146,6 +147,62 @@ void settingState() { } } + @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes + @Nested + @DisplayName("handle stable builds") + final class StableBuild { + + private final Build previousBuild = passingBuild(); + private final BuildState previousBuildState = buildStateFrom(previousBuild); + + private final Build newBuild = nextPassingBuild(); + private final BuildState newBuildState = buildStateFrom(newBuild); + + @BeforeEach + void setUp() { + travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); + var checkRepoFailure = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().receivesCommand(checkRepoFailure); + travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); + var checkRepoRecovery = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().receivesCommand(checkRepoRecovery); + } + + @Test + @DisplayName("producing BuildStable event") + void producingEvent() { + var stateChange = BuildStateChange + .newBuilder() + .setPreviousValue(previousBuildState) + .setNewValue(newBuildState) + .vBuild(); + var buildFailed = BuildStable + .newBuilder() + .setId(repositoryId) + .setChange(stateChange) + .vBuild(); + context().assertEvent(buildFailed); + } + + @Test + @DisplayName("setting process state") + void settingState() { + var expectedState = RepositoryBuild + .newBuilder() + .setId(repositoryId) + .setBuildState(newBuildState) + .vBuild(); + context().assertState(repositoryId, RepositoryBuild.class) + .isEqualTo(expectedState); + } + } + private static BuildsResponse singleBuild(Build build) { return BuildsResponse .newBuilder() @@ -165,6 +222,18 @@ private static Build passingBuild() { .buildPartial(); } + private static Build nextPassingBuild() { + return Build + .newBuilder() + .setId(123154L) + .setNumber("43") + .setState("passed") + .setPreviousState("passed") + .setRepository(webRepository()) + .setCommit(stableCommit()) + .buildPartial(); + } + private static Build failedBuild() { return Build .newBuilder() @@ -173,7 +242,24 @@ private static Build failedBuild() { .setState("failed") .setPreviousState("failed") .setRepository(webRepository()) - .setCommit(luckyCommit()) + .setCommit(fatefulCommit()) + .buildPartial(); + } + + private static Commit stableCommit() { + var compareUrl = "https://github.com/SpineEventEngine/web/compare/04694f26f24a...afc1b76bf93c"; + var author = Commit.Author + .newBuilder() + .setName("God") + .buildPartial(); + return Commit + .newBuilder() + .setId(668) + .setCompareUrl(compareUrl) + .setSha("afc1b76bf93c4dadf86075280da623f947e1434b") + .setAuthor(author) + .setCommittedAt("2020-06-06T18:30:00Z") + .setMessage("May the heaven be on earth.") .buildPartial(); } @@ -192,7 +278,6 @@ private static Commit luckyCommit() { .setCommittedAt("2020-06-06T18:00:00Z") .setMessage("No you're not. Fixing the world.") .buildPartial(); - } private static Commit fatefulCommit() { From 7eb02cf9faeb1963973c02de0b323221a3403b22 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 19:36:45 +0300 Subject: [PATCH 180/492] Add BuildStates test --- .../chatbot/server/github/BuildStates.java | 4 +-- .../server/github/BuildStatesTest.java | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java index 6f3580f6..59fb4bb7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java @@ -29,14 +29,14 @@ * A utility class for working with {@link io.spine.chatbot.github.repository.build.BuildState.State * BuildState.State}s. */ -public final class BuildStates { +final class BuildStates { /** Prevents instantiation of this utility class. **/ private BuildStates() { } /** Creates an instance of the build state of out its string representation. */ - public static BuildState.State buildStateFrom(String state) { + static BuildState.State buildStateFrom(String state) { checkNotNull(state); for (BuildState.State buildState : BuildState.State.values()) { if (state.equalsIgnoreCase(buildState.name())) { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java new file mode 100644 index 00000000..3632ef21 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("BuildStates should") +final class BuildStatesTest extends UtilityClassTest { + + BuildStatesTest() { + super(BuildStates.class); + } +} From 7366029acc3fb8ce6558cdd8982daf3d59fb2e17 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 19:39:22 +0300 Subject: [PATCH 181/492] Ensure unknown build states are not supported --- .../spine/chatbot/server/github/BuildStatesTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java index 3632ef21..c03dd57d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java @@ -22,6 +22,10 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.github.BuildStates.buildStateFrom; +import static org.junit.jupiter.api.Assertions.assertThrows; @DisplayName("BuildStates should") final class BuildStatesTest extends UtilityClassTest { @@ -29,4 +33,11 @@ final class BuildStatesTest extends UtilityClassTest { BuildStatesTest() { super(BuildStates.class); } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + @DisplayName("not accept unknown build states") + void notAcceptUnknownStates() { + assertThrows(IllegalArgumentException.class, () -> buildStateFrom("unknown")); + } } From 13197c386ae4d1b6a6a0621397853a6c6d657834 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 19 Jun 2020 19:53:43 +0300 Subject: [PATCH 182/492] Expand Identifiers tests --- .../server/google/chat/IdentifiersTest.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java index 8e2e1322..cdd7ca01 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java @@ -20,8 +20,24 @@ package io.spine.chatbot.server.google.chat; +import io.spine.chatbot.google.chat.MessageId; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.testing.UtilityClassTest; +import io.spine.validate.ValidationException; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; +import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; @DisplayName("GoogleChat Identifiers should") final class IdentifiersTest extends UtilityClassTest { @@ -29,4 +45,51 @@ final class IdentifiersTest extends UtilityClassTest { IdentifiersTest() { super(Identifiers.class); } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @TestInstance(PER_CLASS) + @Nested + @DisplayName("not accept invalid") + final class NotAcceptInvalid { + + @ParameterizedTest + @MethodSource("spaceIdsSource") + @DisplayName("space IDs") + void spaceIds(String value) { + Assertions.assertThrows(ValidationException.class, () -> spaceIdOf(value)); + } + + @ParameterizedTest + @MethodSource("messageIdsSource") + @DisplayName("space IDs") + void messageIds(String value) { + Assertions.assertThrows(ValidationException.class, () -> messageIdOf(value)); + } + + private Stream spaceIdsSource() { + return Stream.of("spaces/", "spacs/12415", "", " "); + } + + private Stream messageIdsSource() { + return Stream.of("spaces/", "spaces/qwe124", "spaces/eqwt23/messages/", "", " "); + } + } + + @Test + @DisplayName("create space ID") + void createSpaceId() { + var spaceId = "spaces/qew21466"; + assertThat(spaceIdOf(spaceId)).isEqualTo(SpaceId.newBuilder() + .setValue(spaceId) + .buildPartial()); + } + + @Test + @DisplayName("create message ID") + void createMessageId() { + var messageId = "spaces/qew21466/messages/123112111"; + assertThat(messageIdOf(messageId)).isEqualTo(MessageId.newBuilder() + .setValue(messageId) + .buildPartial()); + } } From 5c8eef75ecf10c6a8d703472053c9fb7daf6ddac Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 16:21:55 +0300 Subject: [PATCH 183/492] Add entity level docs --- .../chatbot/server/google/chat/SpaceAggregate.java | 8 ++++++++ .../chatbot/server/google/chat/ThreadAggregate.java | 12 ++++++++++++ .../google/chat/ThreadAggregateRepository.java | 3 +++ .../server/google/chat/ThreadChatProcess.java | 12 ++++++++++++ .../google/chat/ThreadChatProcessRepository.java | 3 +++ 5 files changed, 38 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 05e14135..29b1da47 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -29,8 +29,16 @@ import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; +/** + * A room or direct message chat in the Google Chat. + * + *

Whenever the ChatBot is added to the space, the space is registered in the context. + */ final class SpaceAggregate extends Aggregate implements Logging { + /** + * Registers the space in the context. + */ @Assign SpaceRegistered handle(RegisterSpace c) { _info().log("Registering space `%s`.", idAsString()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index 50365b1b..d5221c6f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -31,8 +31,17 @@ import io.spine.server.aggregate.Apply; import io.spine.server.event.React; +/** + * A thread in the Google Chat room. + * + *

A new thread is initialized as early as a new conversation is started in the room. + * It is being initialized with the creation of the first message of the conversation. + */ final class ThreadAggregate extends Aggregate implements Logging { + /** + * Initializes the thread information upon the creation of the thread. + */ @React ThreadInitialized on(ThreadCreated e) { _info().log("A new thread `%s` created.", idAsString()); @@ -50,6 +59,9 @@ private void on(ThreadInitialized e) { .setSpaceId(e.getSpaceId()); } + /** + * Acknowledges creation of a new thread message. + */ @React MessageAdded on(MessageCreated e) { var messageId = e.getId(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java index ce8186f3..7507adc9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java @@ -28,6 +28,9 @@ import static io.spine.server.route.EventRoute.withId; +/** + * The repository for {@link ThreadAggregate}s. + */ final class ThreadAggregateRepository extends AggregateRepository { @Override diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 365b6d43..240c3372 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -45,12 +45,18 @@ import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; +/** + * A process of notifying thread members about the changes in the watched resouces. + */ final class ThreadChatProcess extends ProcessManager implements Logging { @LazyInit private @MonotonicNonNull GoogleChatClient googleChatClient; + /** + * Notifies thread members about a failed CI build. + */ @React Pair> on(@External BuildFailed e) { var change = e.getChange(); @@ -61,6 +67,12 @@ Pair> on(@External BuildFailed e) { return processBuildStateUpdate(buildState, repositoryId); } + /** + * Notifies thread members about a recovered CI build. + * + *

The build is considered a recovered when it changes its state from + * {@code failed} to {@code passing}. + */ @React Pair> on(@External BuildRecovered e) { var change = e.getChange(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java index 61869ed6..b66fc948 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -37,6 +37,9 @@ import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; import static io.spine.server.route.EventRoute.withId; +/** + * The repository for {@link ThreadChatProcess}es. + */ final class ThreadChatProcessRepository extends ProcessManagerRepository { From 47d3a9fa4407261e1d1828bec19cbeddd77aac80 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:04:52 +0300 Subject: [PATCH 184/492] Add and improve javadocs. Reformat them according to the latest vision. --- .../java/io/spine/chatbot/Application.java | 19 ++++++++--- .../java/io/spine/chatbot/BeanFactory.java | 29 ++++++++++++++++- .../chatbot/ChatBotServerEnvironment.java | 8 +++-- .../chatbot/IncomingEventsController.java | 2 +- .../spine/chatbot/client/ChatBotClient.java | 22 +++++++++---- .../chatbot/delivery/DsDeliveryFactory.java | 4 ++- .../delivery/LocalDeliveryFactory.java | 4 ++- .../spine/chatbot/delivery/ShardDelivery.java | 31 ++++++++++++++++-- .../PubsubPushNotificationDeserializer.java | 30 ----------------- .../spine/chatbot/jackson/package-info.java | 32 ------------------- .../chatbot/server/github/BuildStates.java | 8 +++-- .../chatbot/server/github/GitHubContext.java | 17 +++++++--- .../chatbot/server/github/Identifiers.java | 12 +++++-- .../server/github/OrganizationAggregate.java | 9 ++++++ .../github/OrganizationInitProcess.java | 25 +++++++++++---- .../github/OrganizationInitRepository.java | 3 ++ .../OrganizationRepositoriesProjection.java | 11 +++++++ .../OrganizationRepositoriesRepository.java | 3 ++ .../server/github/RepositoryAggregate.java | 8 +++++ .../server/github/RepositoryAwareEvent.java | 5 +++ .../server/github/RepositoryBuildProcess.java | 20 ++++++++++++ .../github/RepositoryBuildRepository.java | 3 ++ .../server/google/chat/GoogleChatContext.java | 24 ++++++++++---- .../server/google/chat/Identifiers.java | 16 +++++++--- .../server/google/chat/ThreadResources.java | 4 ++- .../src/main/java/io/spine/net/Urls.java | 16 +++++++--- travis-ci.http | 2 +- 27 files changed, 253 insertions(+), 114 deletions(-) delete mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java delete mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index b4211f51..ac6e51e6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -45,17 +45,26 @@ public final class Application { static final String SERVER_NAME = "ChatBotServer"; - /** Prevents direct instantiation. **/ + /** + * Prevents direct instantiation. + */ private Application() { } - /** Starts the application. **/ + /** + * Starts the application. + * + *

Performs bounded contexts initialization, starts Spine {@link Server} and runs + * the {@link Micronaut}. + */ public static void main(String[] args) { initializeSpine(); Micronaut.run(Application.class, args); } - /** Initializes Spine server environment and starts Spine {@link Server}. **/ + /** + * Initializes Spine server environment and starts Spine {@link Server}. + */ private static void initializeSpine() { ChatBotServerEnvironment.initializeEnvironment(); var gitHubContext = GitHubContext @@ -67,7 +76,9 @@ private static void initializeSpine() { startSpineServer(gitHubContext, googleChatContext); } - /** Starts Spine in-process server. **/ + /** + * Starts Spine in-process server. + */ @VisibleForTesting static void startSpineServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index c9695663..e1032c11 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -20,11 +20,16 @@ package io.spine.chatbot; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.context.annotation.Bean; import io.micronaut.context.annotation.Factory; -import io.spine.chatbot.jackson.PubsubPushNotificationDeserializer; +import io.spine.json.Json; import javax.inject.Singleton; +import java.io.IOException; /** * Creates Micronaut context bean definitions. @@ -41,4 +46,26 @@ final class BeanFactory { PubsubPushNotificationDeserializer pubsubDeserializer() { return new PubsubPushNotificationDeserializer(); } + + /** + * Spine-based {@link PubsubPushNotification} Jackson deserializer. + */ + private static final class PubsubPushNotificationDeserializer + extends JsonDeserializer { + + /** + * Deserializes {@link PubsubPushNotification} JSON string into a Protobuf message. + */ + @Override + public PubsubPushNotification deserialize(JsonParser parser, DeserializationContext ctxt) { + try { + var protoJson = parser.readValueAsTree() + .toString(); + var result = Json.fromJson(protoJson, PubsubPushNotification.class); + return result; + } catch (IOException e) { + throw new RuntimeException("Unable to deserialize PubsubPushNotification json.", e); + } + } + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index 6a1ee06f..81beab4b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -43,11 +43,15 @@ */ final class ChatBotServerEnvironment { - /** Prevents instantiation of this utility class. **/ + /** + * Prevents instantiation of this utility class. + */ private ChatBotServerEnvironment() { } - /** Initializes {@link ServerEnvironment} for ChatBot. **/ + /** + * Initializes {@link ServerEnvironment} for ChatBot. + */ static void initializeEnvironment() { var se = ServerEnvironment.instance(); var environment = Environment.instance(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index f723132a..78d657ab 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -85,7 +85,7 @@ private static void onBotAddedToSpace(Space space, ChatBotClient client) { .setThreaded(isThreaded(space)) .setId(Identifiers.spaceIdOf(space.getName())) .vBuild(); - client.postSyncCommand(registerSpace, SpaceRegistered.class); + client.post(registerSpace, SpaceRegistered.class); } private static boolean isThreaded(Space space) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java index d22880b6..09a9617e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java @@ -29,6 +29,7 @@ import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.client.Client; import io.spine.client.ClientRequest; +import io.spine.client.CommandRequest; import io.spine.client.Subscription; import java.util.Collection; @@ -49,7 +50,9 @@ private ChatBotClient(Client client) { this.client = client; } - /** Creates a new in-process client configured for the specified server. **/ + /** + * Creates a new in-process client configured for the specified server. + */ public static ChatBotClient inProcessClient(String serverName) { Client client = Client .inProcess(serverName) @@ -57,12 +60,19 @@ public static ChatBotClient inProcessClient(String serverName) { return new ChatBotClient(client); } - /** Returns Spine client guest request. **/ + /** + * Returns Spine client guest request. + */ public ClientRequest asGuest() { return client.asGuest(); } - /** Cancels the passed subscription. **/ + /** + * Cancels the passed subscription. + * + * @see io.spine.client.Subscriptions#cancel(Subscription) + * @see CommandRequest#post() + */ @CanIgnoreReturnValue public boolean cancelSubscription(Subscription subscription) { return client.subscriptions() @@ -94,12 +104,12 @@ public ImmutableList listRepositories() { * Posts a command and waits synchronously till the expected outcome event is published. */ public void - postSyncCommand(CommandMessage command, Class expectedOutcome) { - postSyncCommand(command, expectedOutcome, 1); + post(CommandMessage command, Class expectedOutcome) { + post(command, expectedOutcome, 1); } private void - postSyncCommand(CommandMessage command, Class expectedOutcome, int expectedEvents) { + post(CommandMessage command, Class expectedOutcome, int expectedEvents) { var latch = new CountDownLatch(expectedEvents); var subscriptions = client .asGuest() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java index 9a16bed3..3d4446d8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java @@ -44,7 +44,9 @@ private DsDeliveryFactory(DatastoreStorageFactory factory) { storageFactory = factory; } - /** Creates a new instance of the delivery factory. **/ + /** + * Creates a new instance of the delivery factory. + */ static DeliveryFactory instance(DatastoreStorageFactory storageFactory) { return new DsDeliveryFactory(storageFactory); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java index 0132b8b0..97e70851 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java @@ -37,7 +37,9 @@ final class LocalDeliveryFactory implements DeliveryFactory { /** A singleton instance of the local delivery factory. **/ static final LocalDeliveryFactory instance = new LocalDeliveryFactory(); - /** Prevents instantiation of this class. **/ + /** + * Prevents instantiation of this class. + */ private LocalDeliveryFactory() { } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java index 8624e3f1..4bc3b01f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -1,3 +1,23 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package io.spine.chatbot.delivery; import io.spine.logging.Logging; @@ -17,12 +37,16 @@ private ShardDelivery(ShardIndex shard) { this.shard = shard; } - /** Delivers the {@code message}. **/ + /** + * Delivers the {@code message}. + */ static void deliver(ShardedRecord message) { deliverFrom(message.shardIndex()); } - /** Delivers messages from the {@code shard}. **/ + /** + * Delivers messages from the {@code shard}. + */ static void deliverFrom(ShardIndex shard) { var delivery = new ShardDelivery(shard); delivery.deliverNow(); @@ -30,7 +54,8 @@ static void deliverFrom(ShardIndex shard) { private void deliverNow() { var server = ServerEnvironment.instance(); - var nodeId = server.nodeId().getValue(); + var nodeId = server.nodeId() + .getValue(); var indexValue = shard.getIndex(); _trace().log("Delivering messages from shard with index `%d`. NodeId=%s.", indexValue, nodeId); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java b/google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java deleted file mode 100644 index 5434b8a7..00000000 --- a/google-chat-bot/src/main/java/io/spine/chatbot/jackson/PubsubPushNotificationDeserializer.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.spine.chatbot.jackson; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.google.pubsub.v1.PubsubPushNotification; -import io.spine.json.Json; - -import java.io.IOException; - -/** - * Spine-based {@link PubsubPushNotification} Jackson deserializer. - */ -public final class PubsubPushNotificationDeserializer extends JsonDeserializer { - - /** - * Deserializes {@link PubsubPushNotification} JSON string into a Protobuf message. - */ - @Override - public PubsubPushNotification deserialize(JsonParser parser, DeserializationContext ctxt) { - try { - var protoJson = parser.readValueAsTree() - .toString(); - var result = Json.fromJson(protoJson, PubsubPushNotification.class); - return result; - } catch (IOException e) { - throw new RuntimeException("Unable to deserialize PubsubPushNotification json.", e); - } - } -} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java deleted file mode 100644 index 025b3c46..00000000 --- a/google-chat-bot/src/main/java/io/spine/chatbot/jackson/package-info.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * This package jackson utilities. - * - * @see jackson - */ -@CheckReturnValue -@ParametersAreNonnullByDefault -package io.spine.chatbot.jackson; - -import com.google.errorprone.annotations.CheckReturnValue; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java index 59fb4bb7..43843102 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java @@ -31,11 +31,15 @@ */ final class BuildStates { - /** Prevents instantiation of this utility class. **/ + /** + * Prevents instantiation of this utility class. + */ private BuildStates() { } - /** Creates an instance of the build state of out its string representation. */ + /** + * Creates an instance of the build state of out its string representation. + */ static BuildState.State buildStateFrom(String state) { checkNotNull(state); for (BuildState.State buildState : BuildState.State.values()) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 4f1225fb..65d68d83 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -39,12 +39,13 @@ public final class GitHubContext { private final BoundedContextBuilder contextBuilder; - /** Prevents instantiation of this utility class. **/ private GitHubContext(TravisClient travisClient) { this.contextBuilder = configureContextBuilder(travisClient); } - /** Returns the context builder associated with the GitHub context. **/ + /** + * Returns the context builder associated with the GitHub context. + */ public BoundedContextBuilder contextBuilder() { return this.contextBuilder; } @@ -59,12 +60,16 @@ private static BoundedContextBuilder configureContextBuilder(TravisClient travis .add(new RepositoryBuildRepository(travisClient)); } - /** Creates a new builder of the GitHub context. **/ + /** + * Creates a new builder of the GitHub context. + */ public static Builder newBuilder() { return new Builder(); } - /** A Builder for configuring GitHub context. **/ + /** + * A Builder for configuring GitHub context. + */ public static final class Builder { private TravisClient travisClient; @@ -72,7 +77,9 @@ public static final class Builder { private Builder() { } - /** Sets Travis CI client to be used within the context. **/ + /** + * Sets Travis CI client to be used within the context. + */ public Builder setTravis(TravisClient travisClient) { checkNotNull(travisClient); this.travisClient = travisClient; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java index e52aae7e..af946927 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java @@ -28,11 +28,15 @@ */ public final class Identifiers { - /** Prevents instantiation of this utility class. **/ + /** + * Prevents instantiation of this utility class. + */ private Identifiers() { } - /** Creates a new {@link OrganizationId} out of the specified {@code name}. **/ + /** + * Creates a new {@link OrganizationId} out of the specified {@code name}. + */ public static OrganizationId organizationIdOf(String name) { return OrganizationId .newBuilder() @@ -40,7 +44,9 @@ public static OrganizationId organizationIdOf(String name) { .vBuild(); } - /** Creates a new {@link RepositoryId} out of the specified {@code slug}. **/ + /** + * Creates a new {@link RepositoryId} out of the specified {@code slug}. + */ public static RepositoryId repositoryIdOf(String slug) { return RepositoryId .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 8ed2b366..2c9bb3ba 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -29,10 +29,19 @@ import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; +/** + * A GitHub organization. + * + *

The ChatBot watches organization resources and the organization is the root entity + * the resources are organized around. + */ final class OrganizationAggregate extends Aggregate implements Logging { + /** + * Registers a new organization. + */ @Assign OrganizationRegistered handle(RegisterOrganization c) { _info().log("Registering organization `%s`.", idAsString()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java index a69d4b4c..dbf810d5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java @@ -43,6 +43,12 @@ import static io.spine.net.Urls.travisRepoUrlFor; import static io.spine.net.Urls.urlOfSpec; +/** + * Spine Event Engine organization initialization process. + * + *

Registers Spine organization and the watched {@link #WATCHED_REPOS repositories} upon adding + * the ChatBot to the space. + */ final class OrganizationInitProcess extends ProcessManager implements Logging { @@ -57,6 +63,13 @@ final class OrganizationInitProcess @LazyInit private @MonotonicNonNull TravisClient travisClient; + /** + * Registers {@link #SPINE_ORGANIZATION Spine} organization and watched resources that are + * currently available in the Travis CI. + * + *

If a particular repository is not available in Travis, it is then skipped + * and not registered. + */ @Command Iterable on(@External SpaceRegistered e) { if (state().getIsInitialized()) { @@ -64,7 +77,7 @@ Iterable on(@External SpaceRegistered e) { } var spaceId = e.getId(); var commands = ImmutableSet.builder(); - commands.add(registerOrganizationCommand(SPINE_ORGANIZATION, spaceId.getValue())); + commands.add(registerOrgCommand(SPINE_ORGANIZATION, spaceId.getValue())); travisClient.queryRepositoriesFor(SPINE_ORG) .getRepositoriesList() .stream() @@ -76,21 +89,19 @@ Iterable on(@External SpaceRegistered e) { return commands.build(); } - private static RegisterRepository registerRepoCommand(Repository repository, - OrganizationId orgId) { - var slug = repository.getSlug(); + private static RegisterRepository registerRepoCommand(Repository repo, OrganizationId orgId) { + var slug = repo.getSlug(); return RegisterRepository .newBuilder() .setOrganization(orgId) .setGithubUrl(githubRepoUrlFor(slug)) .setId(repositoryIdOf(slug)) - .setName(repository.getName()) + .setName(repo.getName()) .setTravisCiUrl(travisRepoUrlFor(slug)) .vBuild(); } - private RegisterOrganization registerOrganizationCommand(OrganizationId spineOrgId, - String spaceName) { + private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, String spaceName) { _info().log("Registering `Spine Event Engine` organization."); return RegisterOrganization .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java index ceafef34..dce4d1fc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java @@ -31,6 +31,9 @@ import static io.spine.chatbot.server.github.OrganizationInitProcess.SPINE_ORGANIZATION; import static io.spine.server.route.EventRoute.withId; +/** + * The repository for Spine Event Engine initialization process. + */ final class OrganizationInitRepository extends ProcessManagerRepository { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java index 3e6f1e7d..e45ea0f4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java @@ -27,14 +27,25 @@ import io.spine.core.Subscribe; import io.spine.server.projection.Projection; +/** + * Organization repositories projection. + * + *

Holds IDs of all registered repositories in the organization. + */ final class OrganizationRepositoriesProjection extends Projection { + /** + * Registers the organization to watch the repositories for. + */ @Subscribe void on(OrganizationRegistered e) { builder().setId(e.getId()); } + /** + * Registers the organization repository. + */ @Subscribe void on(RepositoryRegistered e) { builder().addRepositories(e.getId()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java index c21e3de1..0b2261a2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java @@ -31,6 +31,9 @@ import static io.spine.server.route.EventRoute.noTargets; import static io.spine.server.route.EventRoute.withId; +/** + * The repository for {@link OrganizationRepositories}. + */ final class OrganizationRepositoriesRepository extends ProjectionRepositoryThe ChatBot watches for the repository build status. + */ final class RepositoryAggregate extends Aggregate implements Logging { + /** + * Registers the repository. + */ @Assign RepositoryRegistered handle(RegisterRepository c) { _info().log("Registering repository `%s`.", idAsString()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java index 5836d556..ea969667 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java @@ -36,6 +36,11 @@ @Immutable public interface RepositoryAwareEvent extends RepositoryAware, EventMessage { + /** + * Returns target repository ID as a singleton set. + * + * @apiNote This is a convenience method to be used within the event routing schemas. + */ default Set repository() { return withId(getId()); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java index 0563a79c..05769221 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java @@ -49,6 +49,23 @@ import static io.spine.net.Urls.travisBuildUrlFor; import static io.spine.util.Exceptions.newIllegalStateException; +/** + * A repository build process. + * + *

Performs repository build checks and acknowledges the state of the repository builds. + * As a result, emits build status events such as: + * + *

    + *
  • {@link BuildFailed} — whenever the build is failed; + *
  • {@link BuildRecovered} — whenever the build state changes from {@code failed} + * to {@code passing}. + *
  • {@link BuildStable} — whenever the build state is {@code passing} and was + * {@code passing} previously. + *
+ * + *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered + * {@link #FAILED_STATUSES failed statuses}. + */ final class RepositoryBuildProcess extends ProcessManager { @@ -59,6 +76,9 @@ final class RepositoryBuildProcess @LazyInit private @MonotonicNonNull TravisClient travisClient; + /** + * Checks the repository build state and propagates the respective events. + */ @Assign EitherOf3 handle(CheckRepositoryBuild c) { var builds = travisClient.queryBuildsFor(id().getValue()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java index 25fdd28c..e8b04b3a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java @@ -25,6 +25,9 @@ import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.server.procman.ProcessManagerRepository; +/** + * The repository for {@link RepositoryBuildProcess}es. + */ final class RepositoryBuildRepository extends ProcessManagerRepository { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index f4702cd8..1e980dc9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -37,17 +37,20 @@ public final class GoogleChatContext { private final BoundedContextBuilder contextBuilder; - /** Prevents instantiation of this utility class. **/ private GoogleChatContext(GoogleChatClient googleChatClient) { this.contextBuilder = configureContextBuilder(googleChatClient); } - /** Returns the context builder associated with the Google Chat context. **/ + /** + * Returns the context builder associated with the Google Chat context. + */ public BoundedContextBuilder contextBuilder() { return this.contextBuilder; } - /** Creates a new instance of the Google Chat context builder. **/ + /** + * Creates a new instance of the Google Chat context builder. + */ private static BoundedContextBuilder configureContextBuilder(GoogleChatClient googleChatClient) { return BoundedContext @@ -57,20 +60,29 @@ public BoundedContextBuilder contextBuilder() { .add(new ThreadChatProcessRepository(googleChatClient)); } - /** Creates a new builder of the Google Chat context. **/ + /** + * Creates a new builder of the Google Chat context. + */ public static Builder newBuilder() { return new Builder(); } - /** A Builder for configuring Google Chat context. **/ + /** + * A Builder for configuring Google Chat context. + */ public static final class Builder { private GoogleChatClient googleChatClient; + /** + * Prevents direct instantiation. + */ private Builder() { } - /** Sets Google Chat client to be used within the context. **/ + /** + * Sets Google Chat client to be used within the context. + */ public Builder setGoogleChatClient(GoogleChatClient googleChatClient) { checkNotNull(googleChatClient); this.googleChatClient = googleChatClient; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java index 1510de76..ac1d34cc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java @@ -31,11 +31,15 @@ */ public final class Identifiers { - /** Prevents instantiation of this utility class. **/ + /** + * Prevents instantiation of this utility class. + */ private Identifiers() { } - /** Creates a new {@link ThreadId} out of the specified {@code value}. **/ + /** + * Creates a new {@link ThreadId} out of the specified {@code value}. + */ public static ThreadId threadIdOf(String value) { checkNotNull(value); return ThreadId @@ -44,7 +48,9 @@ public static ThreadId threadIdOf(String value) { .vBuild(); } - /** Creates a new {@link SpaceId} out of the specified {@code value}. **/ + /** + * Creates a new {@link SpaceId} out of the specified {@code value}. + */ public static SpaceId spaceIdOf(String value) { checkNotNull(value); return SpaceId @@ -53,7 +59,9 @@ public static SpaceId spaceIdOf(String value) { .vBuild(); } - /** Creates a new {@link MessageId} out of the specified {@code value}. **/ + /** + * Creates a new {@link MessageId} out of the specified {@code value}. + */ public static MessageId messageIdOf(String value) { checkNotNull(value); return MessageId diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java index 3f904ed4..3cdedc80 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -33,7 +33,9 @@ public final class ThreadResources { private ThreadResources() { } - /** Creates a new {@link ThreadResource} with the specified {@code name}. **/ + /** + * Creates a new {@link ThreadResource} with the specified {@code name}. + */ public static ThreadResource threadResourceOf(String name) { return ThreadResource .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/net/Urls.java b/google-chat-bot/src/main/java/io/spine/net/Urls.java index 480de6b7..82a4c781 100644 --- a/google-chat-bot/src/main/java/io/spine/net/Urls.java +++ b/google-chat-bot/src/main/java/io/spine/net/Urls.java @@ -37,14 +37,18 @@ public final class Urls { private Urls() { } - /** Creates a new {@link Url} out of supplied spec. **/ + /** + * Creates a new {@link Url} out of supplied spec. + */ public static Url urlOfSpec(String spec) { return Url.newBuilder() .setSpec(spec) .vBuild(); } - /** Creates a new Travis CI build URL. **/ + /** + * Creates a new Travis CI build URL. + */ public static Url travisBuildUrlFor(String repoSlug, long buildId) { checkNotNull(repoSlug); var spec = format("%s/%s/builds/%d", @@ -52,7 +56,9 @@ public static Url travisBuildUrlFor(String repoSlug, long buildId) { return urlOfSpec(spec); } - /** Creates a new Travis CI repository URL. **/ + /** + * Creates a new Travis CI repository URL. + */ public static Url travisRepoUrlFor(String repoSlug) { checkNotNull(repoSlug); var spec = format("%s/%s", @@ -60,7 +66,9 @@ public static Url travisRepoUrlFor(String repoSlug) { return urlOfSpec(spec); } - /** Creates a new GitHub repository URL. **/ + /** + * Creates a new GitHub repository URL. + */ public static Url githubRepoUrlFor(String repoSlug) { checkNotNull(repoSlug); var spec = format("%s/%s", GITHUB, repoSlug); diff --git a/travis-ci.http b/travis-ci.http index 3ccd26bf..fa4f5d3f 100644 --- a/travis-ci.http +++ b/travis-ci.http @@ -1,6 +1,6 @@ ### List Travis CI builds for a repository -GET https://{{host}}/repo/SpineEventEngine%2Fbase/builds?limit=1&branch.name=master&include=build.commit +GET https://{{host}}/repo/SpineEventEngine%2Fcore-java/builds?limit=3&branch.name=master&include=build.commit Accept: application/json Authorization: token {{token}} Travis-API-Version: 3 From 65e68416a42d0af5c7646b3b5f30bdb2d491906a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:36:52 +0300 Subject: [PATCH 185/492] Add link to Jackson docs --- .../src/main/java/io/spine/chatbot/BeanFactory.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index e1032c11..6561972b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -38,8 +38,7 @@ final class BeanFactory { /** - * Registers {@link com.google.pubsub.v1.PubsubPushNotification push notification} - * Jackson deserializer. + * Registers {@link PubsubPushNotification push notification} Jackson deserializer. */ @Singleton @Bean @@ -49,6 +48,9 @@ PubsubPushNotificationDeserializer pubsubDeserializer() { /** * Spine-based {@link PubsubPushNotification} Jackson deserializer. + * + * @see + * Jackson Deserialization */ private static final class PubsubPushNotificationDeserializer extends JsonDeserializer { From d07a9a2a58a1b56bc757a1cd005e5599d14ab904 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:37:29 +0300 Subject: [PATCH 186/492] Cleanup docs, add missing ones and reformat according to the latest convention. --- .../proto/google/pubsub/v1/pubsub_push.proto | 9 +- .../spine/chatbot/github/identifiers.proto | 1 + .../github/organization_commands.proto | 1 + .../chatbot/github/organization_events.proto | 1 + .../chatbot/github/repository_build.proto | 4 + .../github/repository_build_commands.proto | 2 +- .../github/repository_build_events.proto | 2 +- .../chatbot/github/repository_commands.proto | 4 +- .../chatbot/github/repository_events.proto | 2 +- ...zation_init.proto => spine_org_init.proto} | 11 ++- ...ds.proto => spine_org_init_commands.proto} | 8 +- .../chatbot/google/chat/chat_events.proto | 4 +- .../chatbot/google/chat/identifiers.proto | 1 + .../incoming/incoming_chat_messages.proto | 93 ++++++++++++++++--- .../spine/chatbot/google/chat/space.proto | 2 +- .../chatbot/google/chat/space_commands.proto | 1 + .../chatbot/google/chat/space_events.proto | 1 + .../spine/chatbot/google/chat/thread.proto | 2 +- .../chatbot/google/chat/thread_chat.proto | 5 +- .../chatbot/google/chat/thread_events.proto | 4 +- .../proto/spine/chatbot/travis/travis.proto | 9 +- 21 files changed, 132 insertions(+), 35 deletions(-) rename google-chat-bot/src/main/proto/spine/chatbot/github/{organization_init.proto => spine_org_init.proto} (87%) rename google-chat-bot/src/main/proto/spine/chatbot/github/{organization_init_commands.proto => spine_org_init_commands.proto} (88%) diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto index f2d28498..d76dd3ff 100644 --- a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto +++ b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto @@ -2,9 +2,13 @@ syntax = "proto3"; package google.pubsub.v1; +import "spine/options.proto"; + option java_multiple_files = true; option java_outer_classname = "PubsubPushProto"; option java_package = "com.google.pubsub.v1"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; import "google/pubsub/v1/pubsub.proto"; @@ -12,9 +16,10 @@ import "google/pubsub/v1/pubsub.proto"; message PubsubPushNotification { // Pubsub message. - PubsubMessage message = 1; + PubsubMessage message = 1 [(required) = true]; // The name of the Pubsub subscription that pushed the current notification. // Format is `projects/{project}/subscriptions/{subscription}`. - string subscription = 2; + // + string subscription = 2 [(required) = true, (pattern).regex = "projects/.+/subscriptions/.+"]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index 5c2722fe..395393b5 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -43,5 +43,6 @@ message RepositoryId { // Slug of the repository. // // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. + // string value = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index dfb7254a..28266364 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -34,6 +34,7 @@ import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +// An organization registration command. message RegisterOrganization { OrganizationId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index 773e71d1..ff8b46a3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -34,6 +34,7 @@ import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +// An organization is registered. message OrganizationRegistered { OrganizationId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index ea7c1fb2..3fb965ac 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -59,6 +59,7 @@ enum BuildStateStatusChange { // The build has failed. // // It could be either a build configuration failure or the actual code build issue. + // FAILED = 1; // The build has recovered from the failed state. @@ -102,11 +103,13 @@ message BuildState { // The build has failed. // // Denotes that the developer code could not be successfully built. + // FAILED = 5; // The build configuration has failed. // // Denotes that the build configuration or pre-build steps failed. + // ERRORED = 6; // The build is cancelled. @@ -122,6 +125,7 @@ message BuildState { // The User or Organization that created the build. string created_by = 7; + // A git commit. message Commit { // Checksum the commit has in git and is identified by. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 27472e77..59790b94 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -33,7 +33,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// Requests a check of the repository CI build. +// Check repository CI build state command. message CheckRepositoryBuild { // ID of the repository to perform a check for. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 3de245ef..4e894f4a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -67,4 +67,4 @@ message BuildStable { message BuildInProgress { RepositoryId id = 1 [(required) = true]; -} \ No newline at end of file +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index e19c4262..732025dc 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -34,7 +34,7 @@ import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; -// Registers a new repository in the system. +// Register repository command. message RegisterRepository { RepositoryId id = 1 [(required) = true]; @@ -50,4 +50,4 @@ message RegisterRepository { // ID of the organization the repository is related to if any. OrganizationId organization = 5; -} \ No newline at end of file +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 912024f0..5509c7b2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -34,7 +34,7 @@ import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; -// Denotes that a new repository is registered. +// A repository is registered. message RepositoryRegistered { RepositoryId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init.proto similarity index 87% rename from google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto rename to google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init.proto index 4f019582..bf1fe5cc 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init.proto @@ -26,26 +26,27 @@ import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.init"; -option java_outer_classname = "OrganizationInitProto"; +option java_outer_classname = "SpineOrgInitProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// The initialization process of the default watched organization resources. +// The initialization process of the default watched Spine Event Engine organization resources. // // Ensures that watched resources organization and its repositories are initialized // for a particular Chat Space. -message OrganizationInit { +// +message SpineOrgInit { option (entity).kind = PROCESS_MANAGER; option (entity).visibility = FULL; - // The ID of the organization for which the initialization is performed. + // The ID of Spine Event Engine organization. OrganizationId id = 1; // Name of the Google Chat space associated with the organization in form `spaces/`. string google_chat_space = 2; // Determines whether the organization resources are already initialized. - bool is_initialized = 3; + bool initialized = 3; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init_commands.proto similarity index 88% rename from google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto rename to google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init_commands.proto index 0a1a259a..c4eb0146 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init_commands.proto @@ -26,16 +26,16 @@ import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.init.command"; -option java_outer_classname = "OrganizationInitCommandsProto"; +option java_outer_classname = "SpineOrgInitCommandsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// Requests a check of the repository CI build. -message InitializeOrganization { +// Spine Event Engine organization initialization command. +message InitSpineOrg { - // ID of the organization to perform initialization for. + // ID of the Spine Event Engine organization. OrganizationId id = 1 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index 779bbf96..4721560d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -33,7 +33,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; -// Denotes that a message was created in the space. +// A message created in the space. message MessageCreated { MessageId id = 1 [(required) = true]; @@ -45,7 +45,7 @@ message MessageCreated { ThreadId thread_id = 3; } -// Denotes that a recently created message created a new thread. +// A recently created message created a new thread. message ThreadCreated { ThreadId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto index 6028e329..e9823908 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -44,6 +44,7 @@ message ThreadId { // // E.g. if the thread is denoted to the build status of a GitHub repository, // the GitHub repository slug could be used as the thread ID. + // string value = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index ea47a302..0dab6433 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -30,71 +30,142 @@ option java_outer_classname = "IncomingChatMessagesProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -// Denotes that a message was created in the space. +// A Google Chat incoming event. message ChatEvent { - EventType type = 1; + // type of the event + EventType type = 1 [(required) = true]; - string event_time = 2; + // The timestamp indicating when the event was dispatched. + string event_time = 2 [(required) = true]; - Space space = 3; + // A secret value that bots can use to verify if a request is from Google. + // The token is randomly generated by Google, remains static, and can be obtained from + // the Hangouts Chat API configuration page in the Cloud Console. Developers can + // revoke/regenerate it if needed from the same page. + // + string token = 3; - Message message = 4; + // The bot-defined key for the thread related to the event. + string thread_key = 4; - User user = 5; + // The room or DM in which the event occurred. + Space space = 5; + + // The message that triggered the event, if applicable. + Message message = 6; + + // The user that triggered the event. + User user = 7 [(required) = true]; } +// A message in Hangouts Chat. message Message { - string name = 1; + // Resource name, in the form "spaces/*/messages/*". + string name = 1 [(required) = true, (pattern).regex = "spaces/.+/messages/.+"]; + + // The user who created the message. User sender = 2; + + // The time at which the message was created in Hangouts Chat server. string create_time = 3; + + // Plain-text body of the message. string text = 4; + + // Plain-text body of the message with all bot mentions stripped out. string argumentText = 5; + + // The thread the message belongs to. Thread thread = 6; + // A thread in Hangouts Chat. message Thread { - string name = 1; + + // Resource name, in the form "spaces/*/threads/*". + string name = 1 [(required) = true, (pattern).regex = "spaces/.+/threads/.+"]; } + // Annotations associated with the text in this message. repeated Annotation annotations = 7; + // Annotation metadata of the message message Annotation { + + // Length of the substring in the plain-text message body this annotation corresponds to. uint32 length = 1; + + // Start index (0-based, inclusive) in the plain-text message body this annotation + // corresponds to. + // uint32 start_index = 2; + // The metadata of user mention. UserMention user_mention = 3; + // Annotation metadata for user mentions (@). message UserMention { + + // The type of user mention. string type = 1; + + // The user mentioned. User user = 2; } + + // The type of this annotation. string type = 4; } } - +// A room or DM in Hangouts Chat. message Space { - string name = 1; + + // Resource name of the space, in the form "spaces/*". + string name = 1 [(required) = true, (pattern).regex = "spaces/.+"]; + + // The display name (only if the space is a room). string display_name = 2; + + // The type of a space SpaceType type = 3; } +// A user in Hangouts Chat. message User { - string name = 1; + + // Resource name, in the format "users/*". + string name = 1 [(required) = true, (pattern).regex = "users/.+"]; + + // The user's display name. string displayName = 2; + + // The user's avatar URL. string avatarUrl = 3; + + // The user's email. string email = 4; + + // The user's type. string type = 5; } +// The type of a space. enum SpaceType { + ST_UNKNOWN = 0; + + // Multi-user spaces such as rooms and DMs between humans. ROOM = 1; + + // 1:1 Direct Message between a human and a bot, where all messages are flat. DM = 2; } +// The type of the event the bot is receiving. enum EventType { + ET_UNKNOWN = 0; // A message was sent in a room or direct message. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index f41f0a8b..3d6dc45c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -47,4 +47,4 @@ message Space { // The display name (only if the space is a room). string display_name = 5; -} \ No newline at end of file +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 89e56ae1..7c21b1b2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -32,6 +32,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; +// Register Google Chat space command. message RegisterSpace { SpaceId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto index 2159aac2..27c8f116 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -32,6 +32,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; +// A new Google Chat space registered. message SpaceRegistered { SpaceId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index e10ee707..5e51ab2e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -54,4 +54,4 @@ message ThreadResource { // Resource name of the thread, in the form `spaces//threads/`. string name = 1 [(required) = true]; -} \ No newline at end of file +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto index 6f2f2006..0eced719 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -33,7 +33,10 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; -// A thread in Google Chat room. +// A thread chatting process. +// +// Acknowledges incoming events and publishes messages to a respective thread if needed. +// message ThreadChat { option (entity).kind = PROCESS_MANAGER; option (entity).visibility = FULL; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index 2e660f34..fc8e2f79 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -33,7 +33,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; -// Denotes that a message was created in the space. +// A Google Chat thread initialized. message ThreadInitialized { ThreadId id = 1 [(required) = true]; @@ -45,7 +45,7 @@ message ThreadInitialized { SpaceId space_id = 3 [(required) = true]; } -// Denotes that a message was created in the space. +// A message added to the thead.. message MessageAdded { MessageId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 60dfe38e..0714ef77 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -30,6 +30,10 @@ option java_outer_classname = "TravisCiProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; +// The owner of a resource. +// +// This will be either a user or an organization. +// message Owner { // Value uniquely identifying the owner. @@ -51,6 +55,7 @@ message Repository { // The repository's slug. // // Same as {repository.owner.name}/{repository.name}. + // string slug = 3; } @@ -133,11 +138,13 @@ message Build { // A Travis `builds` API endpoint response. message BuildsResponse { + // Builds fetched by the API call. repeated Build builds = 1; } // A travis `repos` API endpoint response. message RepositoriesResponse { + // Repositories fetched by the API call. repeated Repository repositories = 1; -} \ No newline at end of file +} From af189551057f496b23d54462c1cf5558f1d18867 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:39:21 +0300 Subject: [PATCH 187/492] Cleanup docs formatting --- .../io/spine/chatbot/api/FailFastClient.java | 4 +++- .../chatbot/api/InMemoryGoogleChatClient.java | 12 ++++++++--- .../chatbot/api/InMemoryTravisClient.java | 20 ++++++++++++++----- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java index 207afce1..65419fb8 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java @@ -34,7 +34,9 @@ class FailFastClient implements Logging { /** Determines whether the client should fail if a particular response is not preconfigured. **/ private final boolean failFast; - /** Creates a new client with the specified {@code failFast} behavior. **/ + /** + * Creates a new client with the specified {@code failFast} behavior. + */ FailFastClient(boolean failFast) { this.failFast = failFast; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java index ee0444bf..487dd260 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java @@ -40,12 +40,16 @@ private InMemoryGoogleChatClient(boolean failFast) { super(failFast); } - /** Creates a {@link #failFast} in-memory Google Chat client. **/ + /** + * Creates a {@link #failFast} in-memory Google Chat client. + */ public static InMemoryGoogleChatClient strictClient() { return new InMemoryGoogleChatClient(true); } - /** Creates a lenient in-memory Google Chat client. **/ + /** + * Creates a lenient in-memory Google Chat client. + */ public static InMemoryGoogleChatClient lenientClient() { return new InMemoryGoogleChatClient(false); } @@ -67,7 +71,9 @@ public void setMessageForBuildStatusUpdate(String buildNumber, Message message) sentMessages.put(buildNumber, message); } - /** Resets state of the configured responses. **/ + /** + * Resets state of the configured responses. + */ public void reset() { sentMessages.clear(); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java index eb1288ea..8c52215e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java @@ -40,12 +40,16 @@ private InMemoryTravisClient(boolean failFast) { super(failFast); } - /** Creates a {@link #failFast} in-memory Travis CI client. **/ + /** + * Creates a {@link #failFast} in-memory Travis CI client. + */ public static InMemoryTravisClient strictClient() { return new InMemoryTravisClient(true); } - /** Creates a lenient in-memory Travis CI client. **/ + /** + * Creates a lenient in-memory Travis CI client. + */ public static InMemoryTravisClient lenientClient() { return new InMemoryTravisClient(false); } @@ -66,21 +70,27 @@ public RepositoriesResponse queryRepositoriesFor(String owner) { return result; } - /** Sets up a stub {@code builds} response for a specified {@code repoSlug}. **/ + /** + * Sets up a stub {@code builds} response for a specified {@code repoSlug}. + */ public void setBuildsFor(String repoSlug, BuildsResponse builds) { checkNotNull(repoSlug); checkNotNull(builds); buildsResponses.put(repoSlug, builds); } - /** Sets up a stub {@code repositories} response for a specified {@code owner}. **/ + /** + * Sets up a stub {@code repositories} response for a specified {@code owner}. + */ public void setRepositoriesFor(String owner, RepositoriesResponse repositories) { checkNotNull(owner); checkNotNull(repositories); repositoriesResponses.put(owner, repositories); } - /** Resets state of the configured responses. **/ + /** + * Resets state of the configured responses. + */ public void reset() { buildsResponses.clear(); repositoriesResponses.clear(); From 9320a1bab5ca86a03f55903965e8f5a39d8e25c8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:46:41 +0300 Subject: [PATCH 188/492] Use ThreadResource instead of passing the thread name directly --- .../spine/chatbot/api/BuildStateUpdates.java | 21 ++++++++++--------- .../java/io/spine/chatbot/api/GoogleChat.java | 8 +++---- .../spine/chatbot/api/GoogleChatClient.java | 7 +++---- .../server/google/chat/GoogleChatContext.java | 2 +- .../server/google/chat/ThreadChatProcess.java | 11 +++------- .../spine/chatbot/google/chat/thread.proto | 4 ++-- .../chatbot/api/InMemoryGoogleChatClient.java | 4 ++-- 7 files changed, 26 insertions(+), 31 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java index 168244eb..58f67bb4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java @@ -28,22 +28,23 @@ import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.common.collect.ImmutableList; import io.spine.chatbot.github.repository.build.BuildState; -import io.spine.validate.Validate; +import io.spine.chatbot.google.chat.thread.ThreadResource; +import io.spine.protobuf.Messages; -import javax.annotation.Nullable; - -import static com.google.common.base.Strings.isNullOrEmpty; import static io.spine.chatbot.api.ChatWidgets.cardWith; import static io.spine.chatbot.api.ChatWidgets.linkButton; import static io.spine.chatbot.api.ChatWidgets.sectionWithWidget; import static io.spine.chatbot.api.ChatWidgets.textParagraph; +import static io.spine.validate.Validate.checkValid; /** * A Google Chat utility class that creates {@link BuildState} update messages. */ final class BuildStateUpdates { - /** Prevents instantiation of this utility class. **/ + /** + * Prevents instantiation of this utility class. + */ private BuildStateUpdates() { } @@ -51,11 +52,11 @@ private BuildStateUpdates() { * Creates a new {@link BuildState} update message of of the supplied state and the thread * name. * - *

If the thread name is {@code null} or empty, assumes that the update message should be + *

If the thread has no name set, assumes that the update message should be * sent to a new thread. */ - static Message buildStateMessage(BuildState buildState, @Nullable String threadName) { - Validate.checkValid(buildState); + static Message buildStateMessage(BuildState buildState, ThreadResource thread) { + checkValid(buildState); var cardHeader = new CardHeader() .setTitle(buildState.getRepositorySlug()) .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); @@ -65,8 +66,8 @@ static Message buildStateMessage(BuildState buildState, @Nullable String threadN actions(buildState) ); var message = new Message().setCards(cardWith(cardHeader, sections)); - if (!isNullOrEmpty(threadName)) { - message.setThread(new Thread().setName(threadName)); + if (Messages.isNotDefault(thread)) { + message.setThread(new Thread().setName(thread.getName())); } return message; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java index 89a4f8c2..45ab0026 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java @@ -28,9 +28,9 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.logging.Logging; -import javax.annotation.Nullable; import java.io.IOException; import java.security.GeneralSecurityException; @@ -55,15 +55,15 @@ private GoogleChat(HangoutsChat chat) { /** * Creates default Google Chat client. */ - public static GoogleChatClient defaultGoogleChatClient() { + public static GoogleChatClient instance() { return new GoogleChat(hangoutsChat()); } @Override - public Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { + public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread) { var repoSlug = buildState.getRepositorySlug(); _debug().log("Sending build state update message for repository `%s`.", repoSlug); - var message = buildStateMessage(buildState, threadName); + var message = buildStateMessage(buildState, thread); var result = sendMessage(buildState.getGoogleChatSpace(), message); _debug().log( "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java index b483d505..103b269c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java @@ -22,8 +22,7 @@ import com.google.api.services.chat.v1.model.Message; import io.spine.chatbot.github.repository.build.BuildState; - -import javax.annotation.Nullable; +import io.spine.chatbot.google.chat.thread.ThreadResource; /** * Google Chat API client abstraction. @@ -36,9 +35,9 @@ public interface GoogleChatClient { /** * Sends {@link BuildState} status message to a related space and thread. * - *

If the thread name is not specified the message is sent to a new thread. + *

If the {@code thread} has no name specified the message is sent to a new thread. * * @return a sent message */ - Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName); + Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 1e980dc9..a84247ca 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -94,7 +94,7 @@ public Builder setGoogleChatClient(GoogleChatClient googleChatClient) { */ public GoogleChatContext build() { if (googleChatClient == null) { - googleChatClient = GoogleChat.defaultGoogleChatClient(); + googleChatClient = GoogleChat.instance(); } return new GoogleChatContext(googleChatClient); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 240c3372..6aa1af5c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -20,7 +20,6 @@ package io.spine.chatbot.server.google.chat; -import com.google.common.base.Strings; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.chatbot.api.GoogleChatClient; import io.spine.chatbot.github.RepositoryId; @@ -33,6 +32,7 @@ import io.spine.chatbot.google.chat.thread.ThreadChat; import io.spine.core.External; import io.spine.logging.Logging; +import io.spine.protobuf.Messages; import io.spine.server.event.React; import io.spine.server.procman.ProcessManager; import io.spine.server.tuple.Pair; @@ -85,7 +85,7 @@ Pair> on(@External BuildRecovered e) { private Pair> processBuildStateUpdate(BuildState buildState, RepositoryId repositoryId) { - var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, currentThreadName()); + var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, state().getThread()); var messageId = messageIdOf(sentMessage.getName()); var threadId = threadIdOf(repositoryId.getValue()); var spaceId = spaceIdOf(buildState.getGoogleChatSpace()); @@ -114,12 +114,7 @@ Pair> on(@External BuildRecovered e) { } private boolean shouldCreateThread() { - return Strings.isNullOrEmpty(currentThreadName()); - } - - private String currentThreadName() { - return state().getThread() - .getName(); + return Messages.isDefault(state().getThread()); } void setGoogleChatClient(GoogleChatClient googleChatClient) { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index 5e51ab2e..83d9e1b9 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -39,7 +39,7 @@ message Thread { ThreadId id = 1; - // Resource name of the thread, in the form `spaces//threads/`. + // Resource name of the thread. ThreadResource thread = 2; // ID of the space within with the thread is available. @@ -53,5 +53,5 @@ message Thread { message ThreadResource { // Resource name of the thread, in the form `spaces//threads/`. - string name = 1 [(required) = true]; + string name = 1 [(required) = true, (pattern).regex = "spaces/.+/threads/.+"]; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java index 487dd260..14b3423a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java @@ -22,8 +22,8 @@ import com.google.api.services.chat.v1.model.Message; import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.google.chat.thread.ThreadResource; -import javax.annotation.Nullable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -55,7 +55,7 @@ public static InMemoryGoogleChatClient lenientClient() { } @Override - public Message sendBuildStateUpdate(BuildState buildState, @Nullable String threadName) { + public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread) { var stubbedValue = sentMessages.get(buildState.getNumber()); var result = failOrDefault(stubbedValue, buildState.getNumber(), new Message()); return result; From a942eb3949f7b7c5922d09772eaa237626612f20 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:47:09 +0300 Subject: [PATCH 189/492] remove duplicate option --- .../src/main/proto/google/pubsub/v1/pubsub_push.proto | 1 - 1 file changed, 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto index d76dd3ff..2205e71d 100644 --- a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto +++ b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto @@ -4,7 +4,6 @@ package google.pubsub.v1; import "spine/options.proto"; -option java_multiple_files = true; option java_outer_classname = "PubsubPushProto"; option java_package = "com.google.pubsub.v1"; option java_multiple_files = true; From 505a3fd92250d1570ca37518d2ccdc3b84d507dd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 17:58:07 +0300 Subject: [PATCH 190/492] Rename generic OrganizationInitProcess to SpineOrgInitProcess. Still keep the protos definitions, as we might want to convert the process to a generic one at some point. --- .../spine/chatbot/server/github/GitHubContext.java | 2 +- ...tionInitProcess.java => SpineOrgInitProcess.java} | 8 +++++--- ...itRepository.java => SpineOrgInitRepository.java} | 12 ++++++------ ...{spine_org_init.proto => organization_init.proto} | 8 ++++---- ...mmands.proto => organization_init_commands.proto} | 8 ++++---- ...ProcessTest.java => SpineOrgInitProcessTest.java} | 6 +++--- 6 files changed, 23 insertions(+), 21 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{OrganizationInitProcess.java => SpineOrgInitProcess.java} (97%) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{OrganizationInitRepository.java => SpineOrgInitRepository.java} (82%) rename google-chat-bot/src/main/proto/spine/chatbot/github/{spine_org_init.proto => organization_init.proto} (88%) rename google-chat-bot/src/main/proto/spine/chatbot/github/{spine_org_init_commands.proto => organization_init_commands.proto} (88%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{OrganizationInitProcessTest.java => SpineOrgInitProcessTest.java} (94%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 65d68d83..5ec98366 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -56,7 +56,7 @@ private static BoundedContextBuilder configureContextBuilder(TravisClient travis .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) .add(new OrganizationRepositoriesRepository()) - .add(new OrganizationInitRepository(travisClient)) + .add(new SpineOrgInitRepository(travisClient)) .add(new RepositoryBuildRepository(travisClient)); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index dbf810d5..11a78fac 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -49,7 +49,7 @@ *

Registers Spine organization and the watched {@link #WATCHED_REPOS repositories} upon adding * the ChatBot to the space. */ -final class OrganizationInitProcess +final class SpineOrgInitProcess extends ProcessManager implements Logging { @@ -58,6 +58,8 @@ final class OrganizationInitProcess private static final ImmutableList WATCHED_REPOS = ImmutableList.of( "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" ); + + /** The initialization process ID. **/ static final OrganizationId SPINE_ORGANIZATION = organizationIdOf(SPINE_ORG); @LazyInit @@ -72,7 +74,7 @@ final class OrganizationInitProcess */ @Command Iterable on(@External SpaceRegistered e) { - if (state().getIsInitialized()) { + if (state().isInitialized()) { return ImmutableSet.of(); } var spaceId = e.getId(); @@ -85,7 +87,7 @@ Iterable on(@External SpaceRegistered e) { .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) .forEach(commands::add); builder().setGoogleChatSpace(spaceId.getValue()) - .setIsInitialized(true); + .setInitialized(true); return commands.build(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java similarity index 82% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java index dce4d1fc..0296c9d5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java @@ -28,18 +28,18 @@ import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.route.EventRouting; -import static io.spine.chatbot.server.github.OrganizationInitProcess.SPINE_ORGANIZATION; +import static io.spine.chatbot.server.github.SpineOrgInitProcess.SPINE_ORGANIZATION; import static io.spine.server.route.EventRoute.withId; /** - * The repository for Spine Event Engine initialization process. + * The repository for {@link SpineOrgInitProcess}. */ -final class OrganizationInitRepository - extends ProcessManagerRepository { +final class SpineOrgInitRepository + extends ProcessManagerRepository { private final TravisClient travisClient; - OrganizationInitRepository(TravisClient travisClient) { + SpineOrgInitRepository(TravisClient travisClient) { this.travisClient = travisClient; } @@ -51,7 +51,7 @@ protected void setupEventRouting(EventRouting routing) { } @Override - protected void configure(OrganizationInitProcess processManager) { + protected void configure(SpineOrgInitProcess processManager) { processManager.setTravisClient(travisClient); } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto similarity index 88% rename from google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init.proto rename to google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index bf1fe5cc..b5cc3db9 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -26,22 +26,22 @@ import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.init"; -option java_outer_classname = "SpineOrgInitProto"; +option java_outer_classname = "OrganizationInitProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// The initialization process of the default watched Spine Event Engine organization resources. +// The initialization process of the default watched organization resources. // // Ensures that watched resources organization and its repositories are initialized // for a particular Chat Space. // -message SpineOrgInit { +message OrganizationInit { option (entity).kind = PROCESS_MANAGER; option (entity).visibility = FULL; - // The ID of Spine Event Engine organization. + // The ID of the organization for which the initialization is performed. OrganizationId id = 1; // Name of the Google Chat space associated with the organization in form `spaces/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto similarity index 88% rename from google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init_commands.proto rename to google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index c4eb0146..b937fe34 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/spine_org_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -26,16 +26,16 @@ import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; option java_package = "io.spine.chatbot.github.organization.init.command"; -option java_outer_classname = "SpineOrgInitCommandsProto"; +option java_outer_classname = "OrganizationInitCommandsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// Spine Event Engine organization initialization command. -message InitSpineOrg { +// Initialize watched organization resources command. +message InitializeOrganization { - // ID of the Spine Event Engine organization. + // ID of the organization to perform initialization for. OrganizationId id = 1 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java similarity index 94% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 861656d4..05b0dc38 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -31,10 +31,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.OrganizationInitProcess.SPINE_ORGANIZATION; +import static io.spine.chatbot.server.github.SpineOrgInitProcess.SPINE_ORGANIZATION; -@DisplayName("OrganizationInitProcess should") -final class OrganizationInitProcessTest extends GitHubEntityTest { +@DisplayName("SpineOrgInitProcess should") +final class SpineOrgInitProcessTest extends GitHubEntityTest { @Nested @DisplayName("perform initialization of watched spine resources") From 05b2f8144753a8b4d9ec1c974dea8199015191ca Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:00:41 +0300 Subject: [PATCH 191/492] Rename to a shorter name --- .../java/io/spine/chatbot/server/github/GitHubContext.java | 2 +- ...ionRepositoriesProjection.java => OrgReposProjection.java} | 2 +- ...ionRepositoriesRepository.java => OrgReposRepository.java} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{OrganizationRepositoriesProjection.java => OrgReposProjection.java} (97%) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{OrganizationRepositoriesRepository.java => OrgReposRepository.java} (95%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 5ec98366..98b2a0de 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -55,7 +55,7 @@ private static BoundedContextBuilder configureContextBuilder(TravisClient travis .singleTenant(NAME) .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) - .add(new OrganizationRepositoriesRepository()) + .add(new OrgReposRepository()) .add(new SpineOrgInitRepository(travisClient)) .add(new RepositoryBuildRepository(travisClient)); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java index e45ea0f4..1af8daf9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java @@ -32,7 +32,7 @@ * *

Holds IDs of all registered repositories in the organization. */ -final class OrganizationRepositoriesProjection +final class OrgReposProjection extends Projection { /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java index 0b2261a2..383ada7a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationRepositoriesRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java @@ -34,9 +34,9 @@ /** * The repository for {@link OrganizationRepositories}. */ -final class OrganizationRepositoriesRepository +final class OrgReposRepository extends ProjectionRepository { @OverridingMethodsMustInvokeSuper From 89573826a22acf129fe4a640f7d83954611e8666 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:00:58 +0300 Subject: [PATCH 192/492] Handle duplicates gracefully --- .../io/spine/chatbot/server/github/OrgReposProjection.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java index 1af8daf9..e7644bdf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.github; +import com.google.common.collect.Sets; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.chatbot.github.organization.event.OrganizationRegistered; @@ -48,6 +49,9 @@ void on(OrganizationRegistered e) { */ @Subscribe void on(RepositoryRegistered e) { - builder().addRepositories(e.getId()); + var repositories = Sets.newHashSet(builder().getRepositoriesList()); + repositories.add(e.getId()); + builder().clearRepositories() + .addAllRepositories(repositories); } } From fb50aab9ef406395057e0aff6accd73a4b3fd1b8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:02:09 +0300 Subject: [PATCH 193/492] Switch to shorter name --- .../io/spine/chatbot/server/github/GitHubContext.java | 2 +- ...positoryBuildProcess.java => RepoBuildProcess.java} | 2 +- ...ryBuildRepository.java => RepoBuildRepository.java} | 10 +++++----- ...BuildProcessTest.java => RepoBuildProcessTest.java} | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{RepositoryBuildProcess.java => RepoBuildProcess.java} (99%) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{RepositoryBuildRepository.java => RepoBuildRepository.java} (82%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{RepositoryBuildProcessTest.java => RepoBuildProcessTest.java} (98%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 98b2a0de..a427bca8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -57,7 +57,7 @@ private static BoundedContextBuilder configureContextBuilder(TravisClient travis .add(RepositoryAggregate.class) .add(new OrgReposRepository()) .add(new SpineOrgInitRepository(travisClient)) - .add(new RepositoryBuildRepository(travisClient)); + .add(new RepoBuildRepository(travisClient)); } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java similarity index 99% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 05769221..3fe6ffa9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -66,7 +66,7 @@ *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered * {@link #FAILED_STATUSES failed statuses}. */ -final class RepositoryBuildProcess +final class RepoBuildProcess extends ProcessManager { private static final ImmutableSet FAILED_STATUSES = ImmutableSet.of( diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java similarity index 82% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java index e8b04b3a..e3c88243 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryBuildRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java @@ -26,19 +26,19 @@ import io.spine.server.procman.ProcessManagerRepository; /** - * The repository for {@link RepositoryBuildProcess}es. + * The repository for {@link RepoBuildProcess}es. */ -final class RepositoryBuildRepository - extends ProcessManagerRepository { +final class RepoBuildRepository + extends ProcessManagerRepository { private final TravisClient travisClient; - RepositoryBuildRepository(TravisClient client) { + RepoBuildRepository(TravisClient client) { travisClient = client; } @Override - protected void configure(RepositoryBuildProcess processManager) { + protected void configure(RepoBuildProcess processManager) { super.configure(processManager); processManager.setTravisClient(travisClient); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java similarity index 98% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 93bec465..fd761420 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -38,10 +38,10 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; -import static io.spine.chatbot.server.github.RepositoryBuildProcess.buildStateFrom; +import static io.spine.chatbot.server.github.RepoBuildProcess.buildStateFrom; -@DisplayName("RepositoryBuildProcess should") -final class RepositoryBuildProcessTest extends GitHubEntityTest { +@DisplayName("RepoBuildProcess should") +final class RepoBuildProcessTest extends GitHubEntityTest { private static final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/web"); From 2ffad9faebcb5218dacf97254a672540152ea581 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:07:33 +0300 Subject: [PATCH 194/492] Fix field name after proto change --- .../io/spine/chatbot/server/github/SpineOrgInitProcessTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 05b0dc38..c70d0f7f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -70,7 +70,7 @@ void settingState() { var expectedState = OrganizationInit .newBuilder() .setGoogleChatSpace(spaceId.getValue()) - .setIsInitialized(true) + .setInitialized(true) .setId(SPINE_ORGANIZATION) .vBuild(); context().assertState(SPINE_ORGANIZATION, OrganizationInit.class) From 062889778ff6c9edc60857156b6c075cf33a2e29 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:07:47 +0300 Subject: [PATCH 195/492] Suppress errorprone warnings --- .../io/spine/chatbot/server/google/chat/IdentifiersTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java index cdd7ca01..738a9038 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java @@ -46,7 +46,8 @@ final class IdentifiersTest extends UtilityClassTest { super(Identifiers.class); } - @SuppressWarnings("ResultOfMethodCallIgnored") + // nested tests do not work with static classes + @SuppressWarnings({"ClassCanBeStatic", "ResultOfMethodCallIgnored"}) @TestInstance(PER_CLASS) @Nested @DisplayName("not accept invalid") @@ -66,10 +67,12 @@ void messageIds(String value) { Assertions.assertThrows(ValidationException.class, () -> messageIdOf(value)); } + @SuppressWarnings("unused") // method is used as parameterized test source private Stream spaceIdsSource() { return Stream.of("spaces/", "spacs/12415", "", " "); } + @SuppressWarnings("unused") // method is used as parameterized test source private Stream messageIdsSource() { return Stream.of("spaces/", "spaces/qwe124", "spaces/eqwt23/messages/", "", " "); } From c297f776015ea8df073977101090ec4a13f13cd0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:09:14 +0300 Subject: [PATCH 196/492] Prepend context name --- .../github/{Identifiers.java => GitHubIdentifier.java} | 4 ++-- .../io/spine/chatbot/server/github/SpineOrgInitProcess.java | 4 ++-- .../{IdentifiersTest.java => GitHubIdentifierTest.java} | 6 +++--- .../chatbot/server/github/OrganizationAggregateTest.java | 2 +- .../spine/chatbot/server/github/RepoBuildProcessTest.java | 2 +- .../chatbot/server/github/RepositoryAggregateTest.java | 4 ++-- .../spine/chatbot/server/google/chat/IdentifiersTest.java | 2 +- .../chatbot/server/google/chat/ThreadChatProcessTest.java | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{Identifiers.java => GitHubIdentifier.java} (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{IdentifiersTest.java => GitHubIdentifierTest.java} (89%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java index af946927..514a4a03 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java @@ -26,12 +26,12 @@ /** * A utility for working with {@link GitHubContext} identifiers. */ -public final class Identifiers { +public final class GitHubIdentifier { /** * Prevents instantiation of this utility class. */ - private Identifiers() { + private GitHubIdentifier() { } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 11a78fac..bd7a94a4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -37,8 +37,8 @@ import io.spine.server.procman.ProcessManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; -import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; import static io.spine.net.Urls.githubRepoUrlFor; import static io.spine.net.Urls.travisRepoUrlFor; import static io.spine.net.Urls.urlOfSpec; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java similarity index 89% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java index 5cd97e95..0e58553d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/IdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java @@ -24,10 +24,10 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("GitHub Identifiers should") -final class IdentifiersTest extends UtilityClassTest { +@DisplayName("GitHub GitHubIdentifier should") +final class GitHubIdentifierTest extends UtilityClassTest { - IdentifiersTest() { + GitHubIdentifierTest() { super(Identifiers.class); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index f85075cc..a94a5b64 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -30,7 +30,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index fd761420..a78978a3 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; import static io.spine.chatbot.server.github.RepoBuildProcess.buildStateFrom; @DisplayName("RepoBuildProcess should") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 4277a89e..7f654cf8 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -31,8 +31,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.Identifiers.organizationIdOf; -import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java index 738a9038..b0f2ba96 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java @@ -39,7 +39,7 @@ import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -@DisplayName("GoogleChat Identifiers should") +@DisplayName("GoogleChat GitHubIdentifier should") final class IdentifiersTest extends UtilityClassTest { IdentifiersTest() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 3e76243e..1c3932d4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -38,7 +38,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.Identifiers.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; From 1a6f0aa56f44f4e640e7e8319804d0adb14f9f23 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:10:28 +0300 Subject: [PATCH 197/492] Prepend context name to GoogleChatIdentifier --- .../io/spine/chatbot/IncomingEventsController.java | 4 ++-- .../{Identifiers.java => GoogleChatIdentifier.java} | 4 ++-- .../server/google/chat/ThreadChatProcess.java | 6 +++--- .../google/chat/ThreadChatProcessRepository.java | 2 +- .../chatbot/server/github/GitHubIdentifierTest.java | 8 ++++---- .../server/github/SpineOrgInitProcessTest.java | 4 ++-- ...ifiersTest.java => GoogleChatIdentifierTest.java} | 12 ++++++------ .../server/google/chat/SpaceAggregateTest.java | 2 +- .../server/google/chat/ThreadAggregateTest.java | 6 +++--- .../server/google/chat/ThreadChatProcessTest.java | 6 +++--- 10 files changed, 27 insertions(+), 27 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/{Identifiers.java => GoogleChatIdentifier.java} (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/{IdentifiersTest.java => GoogleChatIdentifierTest.java} (90%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 78d657ab..37f9ea14 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -31,7 +31,7 @@ import io.spine.chatbot.google.chat.incoming.ChatEvent; import io.spine.chatbot.google.chat.incoming.Space; import io.spine.chatbot.google.chat.incoming.SpaceType; -import io.spine.chatbot.server.google.chat.Identifiers; +import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; import io.spine.json.Json; import io.spine.logging.Logging; @@ -83,7 +83,7 @@ private static void onBotAddedToSpace(Space space, ChatBotClient client) { .newBuilder() .setDisplayName(space.getDisplayName()) .setThreaded(isThreaded(space)) - .setId(Identifiers.spaceIdOf(space.getName())) + .setId(GoogleChatIdentifier.spaceIdOf(space.getName())) .vBuild(); client.post(registerSpace, SpaceRegistered.class); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java index ac1d34cc..d5c8d16f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/Identifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java @@ -29,12 +29,12 @@ /** * A utility for working with {@link GoogleChatContext} identifiers. */ -public final class Identifiers { +public final class GoogleChatIdentifier { /** * Prevents instantiation of this utility class. */ - private Identifiers() { + private GoogleChatIdentifier() { } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 6aa1af5c..ec4bb4b7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -40,9 +40,9 @@ import java.util.Optional; -import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java index b66fc948..b6a20c2c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -34,7 +34,7 @@ import java.util.Set; -import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; import static io.spine.server.route.EventRoute.withId; /** diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java index 0e58553d..c7b1c620 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java @@ -20,14 +20,14 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.server.google.chat.Identifiers; +import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("GitHub GitHubIdentifier should") -final class GitHubIdentifierTest extends UtilityClassTest { +@DisplayName("GitHubIdentifier should") +final class GitHubIdentifierTest extends UtilityClassTest { GitHubIdentifierTest() { - super(Identifiers.class); + super(GoogleChatIdentifier.class); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index c70d0f7f..2a379c36 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -23,7 +23,7 @@ import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; -import io.spine.chatbot.server.google.chat.Identifiers; +import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; import io.spine.chatbot.travis.RepositoriesResponse; import io.spine.chatbot.travis.Repository; import org.junit.jupiter.api.BeforeEach; @@ -40,7 +40,7 @@ final class SpineOrgInitProcessTest extends GitHubEntityTest { @DisplayName("perform initialization of watched spine resources") final class Init { - private final SpaceId spaceId = Identifiers.spaceIdOf("spaces/qjwrp1441"); + private final SpaceId spaceId = GoogleChatIdentifier.spaceIdOf("spaces/qjwrp1441"); private final Repository repository = Repository .newBuilder() .setId(123312L) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java similarity index 90% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java index b0f2ba96..57cf9d08 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java @@ -35,15 +35,15 @@ import java.util.stream.Stream; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -@DisplayName("GoogleChat GitHubIdentifier should") -final class IdentifiersTest extends UtilityClassTest { +@DisplayName("GoogleChatIdentifier should") +final class GoogleChatIdentifierTest extends UtilityClassTest { - IdentifiersTest() { - super(Identifiers.class); + GoogleChatIdentifierTest() { + super(GoogleChatIdentifier.class); } // nested tests do not work with static classes diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index d12613aa..cdf5113f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -36,7 +36,7 @@ final class SpaceAggregateTest extends GoogleChatEntityTest { @DisplayName("register a space") final class Register { - private final SpaceId spaceId = Identifiers.spaceIdOf("spaces/poqwdpQ21"); + private final SpaceId spaceId = GoogleChatIdentifier.spaceIdOf("spaces/poqwdpQ21"); private final String displayName = "Spine Developers"; @BeforeEach diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index d09f629f..be2147a7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -34,9 +34,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 1c3932d4..3827e84a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -39,9 +39,9 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.messageIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.spaceIdOf; -import static io.spine.chatbot.server.google.chat.Identifiers.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadChatProcess should") From dfceb56b101b3631a2fafd04baf7ed744f6685e5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:11:36 +0300 Subject: [PATCH 198/492] Prepend context name to `NAME` constants --- .../java/io/spine/chatbot/server/github/GitHubContext.java | 6 +++--- .../java/io/spine/chatbot/server/github/package-info.java | 2 +- .../spine/chatbot/server/google/chat/GoogleChatContext.java | 6 +++--- .../io/spine/chatbot/server/google/chat/package-info.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index a427bca8..cf8579c1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -33,9 +33,9 @@ public final class GitHubContext { /** - * The name of the Context. + * The name of the GitHub Context. */ - static final String NAME = "GitHub"; + static final String GIT_HUB_CONTEXT_NAME = "GitHub"; private final BoundedContextBuilder contextBuilder; @@ -52,7 +52,7 @@ public BoundedContextBuilder contextBuilder() { private static BoundedContextBuilder configureContextBuilder(TravisClient travisClient) { return BoundedContext - .singleTenant(NAME) + .singleTenant(GIT_HUB_CONTEXT_NAME) .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) .add(new OrgReposRepository()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java index 2ef31c9f..1d94b1ab 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java @@ -24,7 +24,7 @@ *

This package is annotated with {@code BoundedContext} annotation to mark * entities of this package (and sub-packages if they existed) as parts of the context. */ -@BoundedContext(GitHubContext.NAME) +@BoundedContext(GitHubContext.GIT_HUB_CONTEXT_NAME) @CheckReturnValue @ParametersAreNonnullByDefault package io.spine.chatbot.server.github; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index a84247ca..338c3d2f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -32,8 +32,8 @@ */ public final class GoogleChatContext { - /** The name of the Context. **/ - static final String NAME = "GoogleChat"; + /** The name of the Google Chat Context. **/ + static final String GOOGLE_CHAT_CONTEXT_NAME = "GoogleChat"; private final BoundedContextBuilder contextBuilder; @@ -54,7 +54,7 @@ public BoundedContextBuilder contextBuilder() { private static BoundedContextBuilder configureContextBuilder(GoogleChatClient googleChatClient) { return BoundedContext - .singleTenant(NAME) + .singleTenant(GOOGLE_CHAT_CONTEXT_NAME) .add(SpaceAggregate.class) .add(new ThreadAggregateRepository()) .add(new ThreadChatProcessRepository(googleChatClient)); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java index 677628af..f65d5039 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java @@ -24,7 +24,7 @@ *

This package is annotated with {@code BoundedContext} annotation to mark * entities of this package (and sub-packages if they existed) as parts of the context. */ -@BoundedContext(GoogleChatContext.NAME) +@BoundedContext(GoogleChatContext.GOOGLE_CHAT_CONTEXT_NAME) @CheckReturnValue @ParametersAreNonnullByDefault package io.spine.chatbot.server.google.chat; From acc95475c5bf3972969361335b6c09632bf80e52 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:12:16 +0300 Subject: [PATCH 199/492] Add missing not-null check --- .../io/spine/chatbot/server/google/chat/ThreadResources.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java index 3cdedc80..3d438603 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -22,6 +22,8 @@ import io.spine.chatbot.google.chat.thread.ThreadResource; +import static com.google.common.base.Preconditions.checkNotNull; + /** * An utility for working with {@link ThreadResource}s. */ @@ -37,6 +39,7 @@ private ThreadResources() { * Creates a new {@link ThreadResource} with the specified {@code name}. */ public static ThreadResource threadResourceOf(String name) { + checkNotNull(name); return ThreadResource .newBuilder() .setName(name) From c0a3d39a4d1852455a6cb5c4bbe450b2a0973016 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:18:01 +0300 Subject: [PATCH 200/492] Move google chat APIs to a dedicated package --- .../{ => google/chat}/BuildStateUpdates.java | 10 +++--- .../api/{ => google/chat}/ChatWidgets.java | 2 +- .../api/{ => google/chat}/GoogleChat.java | 4 +-- .../{ => google/chat}/GoogleChatClient.java | 2 +- .../chatbot/api/google/chat/package-info.java | 33 +++++++++++++++++++ .../server/google/chat/GoogleChatContext.java | 4 +-- .../server/google/chat/ThreadChatProcess.java | 2 +- .../chat/ThreadChatProcessRepository.java | 2 +- .../io/spine/chatbot/api/FailFastClient.java | 8 +++-- .../chat}/BuildStateUpdatesTest.java | 2 +- .../{ => google/chat}/ChatWidgetsTest.java | 2 +- .../chat}/InMemoryGoogleChatClient.java | 3 +- .../google/chat/GoogleChatContextTest.java | 2 +- .../google/chat/GoogleChatEntityTest.java | 2 +- 14 files changed, 57 insertions(+), 21 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => google/chat}/BuildStateUpdates.java (92%) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => google/chat}/ChatWidgets.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => google/chat}/GoogleChat.java (97%) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => google/chat}/GoogleChatClient.java (97%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java rename google-chat-bot/src/test/java/io/spine/chatbot/api/{ => google/chat}/BuildStateUpdatesTest.java (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/api/{ => google/chat}/ChatWidgetsTest.java (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/api/{ => google/chat}/InMemoryGoogleChatClient.java (97%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java similarity index 92% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 58f67bb4..6913e5a5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import com.google.api.services.chat.v1.model.CardHeader; import com.google.api.services.chat.v1.model.KeyValue; @@ -31,10 +31,10 @@ import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.protobuf.Messages; -import static io.spine.chatbot.api.ChatWidgets.cardWith; -import static io.spine.chatbot.api.ChatWidgets.linkButton; -import static io.spine.chatbot.api.ChatWidgets.sectionWithWidget; -import static io.spine.chatbot.api.ChatWidgets.textParagraph; +import static io.spine.chatbot.api.google.chat.ChatWidgets.cardWith; +import static io.spine.chatbot.api.google.chat.ChatWidgets.linkButton; +import static io.spine.chatbot.api.google.chat.ChatWidgets.sectionWithWidget; +import static io.spine.chatbot.api.google.chat.ChatWidgets.textParagraph; import static io.spine.validate.Validate.checkValid; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java index fe3211f7..4311fd5c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/ChatWidgets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import com.google.api.services.chat.v1.model.Button; import com.google.api.services.chat.v1.model.Card; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 45ab0026..02a336cd 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; @@ -34,7 +34,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; -import static io.spine.chatbot.api.BuildStateUpdates.buildStateMessage; +import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; /** * Google Chat Hangouts API client. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java index 103b269c..792721ce 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import com.google.api.services.chat.v1.model.Message; import io.spine.chatbot.github.repository.build.BuildState; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java new file mode 100644 index 00000000..07d2a108 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java @@ -0,0 +1,33 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains Google Chat API facade. + * + *

The usage of the Chat API itself it not straight-forward that's why it is recommended to + * use the {@link io.spine.chatbot.api.google.chat.GoogleChatClient facade} instead. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.api.google.chat; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 338c3d2f..c55683f3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -20,8 +20,8 @@ package io.spine.chatbot.server.google.chat; -import io.spine.chatbot.api.GoogleChat; -import io.spine.chatbot.api.GoogleChatClient; +import io.spine.chatbot.api.google.chat.GoogleChat; +import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index ec4bb4b7..8915d914 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.concurrent.LazyInit; -import io.spine.chatbot.api.GoogleChatClient; +import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.event.BuildFailed; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java index b6a20c2c..9af30771 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.GoogleChatClient; +import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.google.chat.ThreadId; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java index 65419fb8..7f91a094 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java @@ -29,7 +29,7 @@ /** * An abstract API client that exposes the {@code fail-fast} concept to the actual test clients. */ -class FailFastClient implements Logging { +public class FailFastClient implements Logging { /** Determines whether the client should fail if a particular response is not preconfigured. **/ private final boolean failFast; @@ -37,7 +37,7 @@ class FailFastClient implements Logging { /** * Creates a new client with the specified {@code failFast} behavior. */ - FailFastClient(boolean failFast) { + protected FailFastClient(boolean failFast) { this.failFast = failFast; } @@ -60,7 +60,9 @@ class FailFastClient implements Logging { * if the client is configured to use the fail-fast approach and the supplied * {@code value} is {@code null} */ - @NonNull V failOrDefault(@Nullable V value, @NonNull K key, @NonNull V defaultValue) { + protected @NonNull V failOrDefault(@Nullable V value, + @NonNull K key, + @NonNull V defaultValue) { if (failFast && value == null) { throw newIllegalStateException( "Response of type `%s` is not configured for the key `%s`.", diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java similarity index 96% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java index c9b127f7..2edf10ef 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/BuildStateUpdatesTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java similarity index 96% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java index 079aa201..c8451cb4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/ChatWidgetsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java similarity index 97% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java index 14b3423a..8a15dbd4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java @@ -18,9 +18,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.chat; import com.google.api.services.chat.v1.model.Message; +import io.spine.chatbot.api.FailFastClient; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.google.chat.thread.ThreadResource; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java index 0ff90c55..64f6dd0c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.google.chat; -import io.spine.chatbot.api.InMemoryGoogleChatClient; +import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java index 509d1a94..fd500e2a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.InMemoryGoogleChatClient; +import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.AfterEach; From 7bcfd6aef9d7828164e99a50e5051e64d54c7621 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:24:25 +0300 Subject: [PATCH 201/492] move Secrets to its own package --- .../java/io/spine/chatbot/api/Travis.java | 1 + .../api/{ => google/secret}/Secrets.java | 10 ++++--- .../api/google/secret/package-info.java | 30 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => google/secret}/Secrets.java (91%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java index be2bdb07..39203d68 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java @@ -21,6 +21,7 @@ package io.spine.chatbot.api; import com.google.protobuf.Message; +import io.spine.chatbot.api.google.secret.Secrets; import io.spine.chatbot.travis.BuildsResponse; import io.spine.chatbot.travis.RepositoriesResponse; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java similarity index 91% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java index 13b8c8b1..ba127e53 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/Secrets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.google.secret; import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; import com.google.cloud.secretmanager.v1.SecretVersionName; @@ -29,20 +29,22 @@ /** * Utility for accessing application secrets stored in Google Secret Manager. */ -final class Secrets { +public final class Secrets { @SuppressWarnings("CallToSystemGetenv") private static final String PROJECT_ID = System.getenv("GCP_PROJECT_ID"); private static final String TRAVIS_API_TOKEN = "TravisApiToken"; - /** Prevents direct instantiation of the utility class. **/ + /** + * Prevents direct instantiation of the utility class. + */ private Secrets() { } /** * Returns Travis CI API access token. */ - static String travisToken() { + public static String travisToken() { try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { var secretVersion = SecretVersionName.of(PROJECT_ID, TRAVIS_API_TOKEN, "latest"); var secret = client.accessSecretVersion(secretVersion) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java new file mode 100644 index 00000000..489f9809 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains Google Secret Manager API facade. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.api.google.secret; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; From 0664a34304cd4bb3b34e3886b443dfb90b042717 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 18:30:37 +0300 Subject: [PATCH 202/492] move Travis to its own package --- .../{ => travis}/JsonProtoBodyHandler.java | 16 +++++++-- .../chatbot/api/{ => travis}/Travis.java | 6 ++-- .../api/{ => travis}/TravisClient.java | 2 +- .../chatbot/api/travis/package-info.java | 35 +++++++++++++++++++ .../chatbot/server/github/GitHubContext.java | 8 ++--- .../server/github/RepoBuildProcess.java | 2 +- .../server/github/RepoBuildRepository.java | 2 +- .../server/github/SpineOrgInitProcess.java | 2 +- .../server/github/SpineOrgInitRepository.java | 2 +- .../chatbot/IncomingEventsControllerTest.java | 2 +- .../{ => travis}/InMemoryTravisClient.java | 3 +- .../server/github/GitHubContextTest.java | 2 +- .../server/github/GitHubEntityTest.java | 2 +- 13 files changed, 65 insertions(+), 19 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => travis}/JsonProtoBodyHandler.java (82%) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => travis}/Travis.java (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/api/{ => travis}/TravisClient.java (97%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java rename google-chat-bot/src/test/java/io/spine/chatbot/api/{ => travis}/InMemoryTravisClient.java (97%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java similarity index 82% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java index 269981e6..6173979e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.travis; import com.google.protobuf.Message; import io.spine.json.Json; @@ -28,7 +28,15 @@ import java.net.http.HttpResponse.ResponseInfo; import java.nio.charset.StandardCharsets; -/** A {@link HttpResponse.BodyHandler BodyHandler} for JSON Protobuf messages. **/ +/** + * A {@link HttpResponse.BodyHandler BodyHandler} for JSON Protobuf messages. + * + *

The handler converts input JSON strings into the Protobuf messages relying on the + * Spine {@link Json} conversion functionality. + * + * @param + * the Protobuf message supplied in the response body + */ final class JsonProtoBodyHandler implements HttpResponse.BodyHandler { private final Class type; @@ -37,7 +45,9 @@ private JsonProtoBodyHandler(Class type) { this.type = type; } - /** Creates a body handler for a specified type. **/ + /** + * Creates a body handler for a specified Protobuf message. + */ static JsonProtoBodyHandler jsonBodyHandler(Class type) { return new JsonProtoBodyHandler<>(type); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index 39203d68..f2945f75 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.travis; import com.google.protobuf.Message; import io.spine.chatbot.api.google.secret.Secrets; @@ -32,7 +32,7 @@ import java.net.http.HttpRequest; import java.nio.charset.StandardCharsets; -import static io.spine.chatbot.api.JsonProtoBodyHandler.jsonBodyHandler; +import static io.spine.chatbot.api.travis.JsonProtoBodyHandler.jsonBodyHandler; import static java.lang.String.format; /** @@ -60,7 +60,7 @@ private Travis(String token) { /** * Creates a new Travis client with the default secure Travis token. */ - public static TravisClient defaultTravisClient() { + public static TravisClient instance() { return new Travis(Secrets.travisToken()); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java index 3e626863..907095b6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.travis; import io.spine.chatbot.travis.BuildsResponse; import io.spine.chatbot.travis.RepositoriesResponse; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java new file mode 100644 index 00000000..22539042 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains Travis CI v3 API client. + * + *

The travis itself does not provide an idiomatic Java client, so the API contains only + * specific required functionality. + * + * @see Travis CI API + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.api.travis; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index cf8579c1..dd02ddfb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -20,8 +20,8 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.Travis; -import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.api.travis.Travis; +import io.spine.chatbot.api.travis.TravisClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -90,11 +90,11 @@ public Builder setTravis(TravisClient travisClient) { * Finishes configuration of the context and builds a new instance. * *

If the {@link #travisClient} was not explicitly configured, uses the - * {@link Travis#defaultTravisClient() default} client. + * {@link Travis#instance() default} client. */ public GitHubContext build() { if (travisClient == null) { - travisClient = Travis.defaultTravisClient(); + travisClient = Travis.instance(); } return new GitHubContext(travisClient); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 3fe6ffa9..ef22bf77 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -24,7 +24,7 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; -import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java index e3c88243..d0c8bcdd 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.server.procman.ProcessManagerRepository; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index bd7a94a4..5cf1df4b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -24,7 +24,7 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; -import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java index 0296c9d5..21294e01 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.github; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.TravisClient; +import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.event.SpaceRegistered; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 4ca999a5..fcf199ad 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -28,7 +28,7 @@ import io.micronaut.http.client.annotation.Client; import io.micronaut.runtime.server.EmbeddedServer; import io.micronaut.test.annotation.MicronautTest; -import io.spine.chatbot.api.InMemoryTravisClient; +import io.spine.chatbot.api.travis.InMemoryTravisClient; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.json.Json; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java similarity index 97% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java index 8c52215e..9a9a37d6 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java @@ -18,8 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot.api.travis; +import io.spine.chatbot.api.FailFastClient; import io.spine.chatbot.travis.BuildsResponse; import io.spine.chatbot.travis.RepositoriesResponse; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java index f2dc87ec..77a516a6 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.InMemoryTravisClient; +import io.spine.chatbot.api.travis.InMemoryTravisClient; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java index 3935aa04..a4f0fe9e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.github; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.InMemoryTravisClient; +import io.spine.chatbot.api.travis.InMemoryTravisClient; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.AfterEach; From e03cd1307cfd951c00c54192feb5da66086a93c6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 23:49:03 +0300 Subject: [PATCH 203/492] Remove `default` from the `instance` method doc --- .../main/java/io/spine/chatbot/api/google/chat/GoogleChat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 02a336cd..8ca4e3c6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -53,7 +53,7 @@ private GoogleChat(HangoutsChat chat) { } /** - * Creates default Google Chat client. + * Creates Google Chat client. */ public static GoogleChatClient instance() { return new GoogleChat(hangoutsChat()); From 983af7eaa1925ec3d6c5a4ea9fe59b9f38bbeabc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sat, 20 Jun 2020 23:50:40 +0300 Subject: [PATCH 204/492] Add notNull check for the message type. --- .../java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java index 6173979e..0d7d51e3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java @@ -28,6 +28,8 @@ import java.net.http.HttpResponse.ResponseInfo; import java.nio.charset.StandardCharsets; +import static com.google.common.base.Preconditions.checkNotNull; + /** * A {@link HttpResponse.BodyHandler BodyHandler} for JSON Protobuf messages. * @@ -49,6 +51,7 @@ private JsonProtoBodyHandler(Class type) { * Creates a body handler for a specified Protobuf message. */ static JsonProtoBodyHandler jsonBodyHandler(Class type) { + checkNotNull(type); return new JsonProtoBodyHandler<>(type); } From ef87a61d1baf33ebb94dd150a26be928ee5c3423 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 00:29:50 +0300 Subject: [PATCH 205/492] Update bootstrap version --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b23968e3..a1a72423 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { implementation("net.ltgt.gradle:gradle-apt-plugin:0.21") implementation("com.github.jengelman.gradle.plugins:shadow:5.2.0") implementation("gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.4.0") - implementation("io.spine.tools:spine-bootstrap:1.5.21") + implementation("io.spine.tools:spine-bootstrap:1.5.23") implementation("net.saliman:gradle-properties-plugin:1.5.1") } From 9f284679eefa848d44c20e6cce064bd48b426b3c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 01:00:04 +0300 Subject: [PATCH 206/492] Drop custom delivery factory and migrate to new ServerEnvironment configuration flow --- .../chatbot/ChatBotServerEnvironment.java | 18 +++++++-------- ...yFactory.java => DistributedDelivery.java} | 23 ++++++------------- ...eliveryFactory.java => LocalDelivery.java} | 11 ++++----- 3 files changed, 21 insertions(+), 31 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/delivery/{DsDeliveryFactory.java => DistributedDelivery.java} (75%) rename google-chat-bot/src/main/java/io/spine/chatbot/delivery/{LocalDeliveryFactory.java => LocalDelivery.java} (90%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index 81beab4b..c6a4d455 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -22,10 +22,13 @@ import com.google.cloud.datastore.DatastoreOptions; import io.spine.base.Environment; -import io.spine.chatbot.delivery.DeliveryFactory; +import io.spine.base.Production; +import io.spine.base.Tests; +import io.spine.chatbot.delivery.LocalDelivery; import io.spine.server.ServerEnvironment; import io.spine.server.storage.StorageFactory; import io.spine.server.storage.datastore.DatastoreStorageFactory; +import io.spine.server.storage.memory.InMemoryStorageFactory; import io.spine.server.transport.memory.InMemoryTransportFactory; /** @@ -38,8 +41,6 @@ * *

Configures the inbox delivery through the Datastore work registry while * in Production environment, otherwise uses local synchronous delivery. - * - * @see DeliveryFactory */ final class ChatBotServerEnvironment { @@ -54,13 +55,12 @@ private ChatBotServerEnvironment() { */ static void initializeEnvironment() { var se = ServerEnvironment.instance(); - var environment = Environment.instance(); var storageFactory = dsStorageFactory(); - var deliveryFactory = DeliveryFactory.instance(environment, storageFactory); - var delivery = deliveryFactory.delivery(); - se.configureStorage(storageFactory); - se.configureTransport(InMemoryTransportFactory.newInstance()); - se.configureDelivery(delivery); + se.use(InMemoryTransportFactory.newInstance(), Production.class); + se.use(LocalDelivery.instance, Production.class); + se.use(LocalDelivery.instance, Tests.class); + se.use(storageFactory, Production.class); + se.use(InMemoryStorageFactory.newInstance(), Tests.class); } private static DatastoreStorageFactory dsStorageFactory() { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java similarity index 75% rename from google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java rename to google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java index 3d4446d8..3a15aa3d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DsDeliveryFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java @@ -27,28 +27,20 @@ import io.spine.server.storage.datastore.DsShardedWorkRegistry; /** - * A {@link Delivery} factory that creates deliveries used in distributed cloud environments. + * A distributed cloud environment {@link Delivery}. * - *

The distributed delivery is based on {@link DatastoreStorageFactory datastore}. - * - *

Uses {@link DsShardedWorkRegistry} as the {@link ShardedWorkRegistry}. + *

The delivery is based on the {@link DatastoreStorageFactory Datastore} and uses + * {@link DsShardedWorkRegistry} as the {@link ShardedWorkRegistry work registry}. */ -final class DsDeliveryFactory implements DeliveryFactory { +final class DistributedDelivery { /** The number of shards used for the signals delivery. **/ private static final int NUMBER_OF_SHARDS = 50; - private final DatastoreStorageFactory storageFactory; - - private DsDeliveryFactory(DatastoreStorageFactory factory) { - storageFactory = factory; - } - /** - * Creates a new instance of the delivery factory. + * Prevents instantiation of this utility class. */ - static DeliveryFactory instance(DatastoreStorageFactory storageFactory) { - return new DsDeliveryFactory(storageFactory); + private DistributedDelivery() { } /** @@ -56,8 +48,7 @@ static DeliveryFactory instance(DatastoreStorageFactory storageFactory) { * *

Uses uniformly sharded strategy and single-tenant inbox storage. */ - @Override - public Delivery delivery() { + public static Delivery instance(DatastoreStorageFactory storageFactory) { var workRegistry = new DsShardedWorkRegistry(storageFactory); var inboxStorage = storageFactory.createInboxStorage(false); var delivery = Delivery diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDelivery.java similarity index 90% rename from google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java rename to google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDelivery.java index 97e70851..0033eac6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDeliveryFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/LocalDelivery.java @@ -32,22 +32,21 @@ /** * A {@link Delivery} factory that creates deliveries for local or test environments. */ -final class LocalDeliveryFactory implements DeliveryFactory { +public final class LocalDelivery { - /** A singleton instance of the local delivery factory. **/ - static final LocalDeliveryFactory instance = new LocalDeliveryFactory(); + /** A singleton instance of the local delivery. **/ + public static final Delivery instance = delivery(); /** * Prevents instantiation of this class. */ - private LocalDeliveryFactory() { + private LocalDelivery() { } /** * Creates a new instance of an in-memory local delivery. */ - @Override - public Delivery delivery() { + private static Delivery delivery() { var delivery = Delivery .newBuilder() .setInboxStorage(singleTenantInboxStorage()) From 356d335a14052e9fa109447aa10aa52ef7bd1c9e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 01:01:44 +0300 Subject: [PATCH 207/492] Refactor Travis client. Use Travis API Query and specific Query instances to determine the actual request that's gonna be executed. --- .../travis/BuildsQuery.java} | 37 +++++----- .../io/spine/chatbot/api/travis/Query.java | 68 +++++++++++++++++++ .../spine/chatbot/api/travis/ReposQuery.java | 44 ++++++++++++ .../io/spine/chatbot/api/travis/Travis.java | 36 +++------- .../chatbot/api/travis/TravisClient.java | 18 +++-- .../chatbot/api/travis/TravisResponse.java | 30 ++++++++ .../server/github/RepoBuildProcess.java | 7 +- .../server/github/SpineOrgInitProcess.java | 5 +- .../proto/spine/chatbot/travis/travis.proto | 8 ++- .../api/travis/InMemoryTravisClient.java | 32 +++------ .../server/github/RepoBuildProcessTest.java | 8 +-- .../github/SpineOrgInitProcessTest.java | 4 +- 12 files changed, 207 insertions(+), 90 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{delivery/DeliveryFactory.java => api/travis/BuildsQuery.java} (55%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java similarity index 55% rename from google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index a3eee3b7..50e4521f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DeliveryFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -18,32 +18,29 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.delivery; - -import io.spine.base.Environment; -import io.spine.server.delivery.Delivery; -import io.spine.server.storage.datastore.DatastoreStorageFactory; +package io.spine.chatbot.api.travis; /** - * A utility class for configuring {@link Delivery} for environments. + * Travis CI builds API query. + * + * @see Find build */ -public interface DeliveryFactory { +public final class BuildsQuery extends Query { - /** - * Creates a new fully-configured delivery. - */ - Delivery delivery(); + private BuildsQuery(String request) { + super(request, BuildsResponse.class); + } /** - * Creates a new instance of a delivery factory for the specified {@code environment} - * and using the {@code storageFactory} if required. + * Creates a repository builds query for a repository with the specified {@code slug}. + * + *

Requests only a single build from the {@code master} branch */ - static DeliveryFactory instance(Environment environment, - DatastoreStorageFactory storageFactory) { - if (environment.isProduction()) { - return DsDeliveryFactory.instance(storageFactory); - } else { - return LocalDeliveryFactory.instance; - } + public static BuildsQuery forRepo(String repoSlug) { + var encodedSlug = encode(repoSlug); + var request = "/repo/" + + encodedSlug + + "/builds?limit=1&branch.name=master&include=build.commit"; + return new BuildsQuery(request); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java new file mode 100644 index 00000000..2b958aa7 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java @@ -0,0 +1,68 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api.travis; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A Travis CI API query. + * + * @param + * type of the expected query execution response + */ +public class Query { + + private final Class responseType; + private final String request; + + /** + * Creates a new API query with the specified {@code request}. + */ + Query(String request, Class responseType) { + this.request = checkNotNull(request); + this.responseType = checkNotNull(responseType); + } + + /** + * Returns query REST request URL. + */ + String request() { + return request; + } + + /** + * Returns query response type. + */ + Class responseType() { + return responseType; + } + + /** + * Encodes passed value using {@link URLEncoder} and standard + * {@link StandardCharsets#UTF_8 UTF_8} charset. + */ + static String encode(String value) { + return URLEncoder.encode(value, StandardCharsets.UTF_8); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java new file mode 100644 index 00000000..44f2a52e --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api.travis; + +/** + * Travis CI repositories API query. + * + * @see + * Repos for owner + */ +public final class ReposQuery extends Query { + + private ReposQuery(String request) { + super(request, RepositoriesResponse.class); + } + + /** + * Creates a repository query for repositories of the specified {@code owner} + * (either a user or an organization). + */ + public static ReposQuery forOwner(String owner) { + var encodedOwner = encode(owner); + var request = "/owner/" + encodedOwner + "/repos"; + return new ReposQuery(request); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index f2945f75..33530793 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -20,17 +20,12 @@ package io.spine.chatbot.api.travis; -import com.google.protobuf.Message; import io.spine.chatbot.api.google.secret.Secrets; -import io.spine.chatbot.travis.BuildsResponse; -import io.spine.chatbot.travis.RepositoriesResponse; import java.io.IOException; import java.net.URI; -import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; -import java.nio.charset.StandardCharsets; import static io.spine.chatbot.api.travis.JsonProtoBodyHandler.jsonBodyHandler; import static java.lang.String.format; @@ -65,38 +60,27 @@ public static TravisClient instance() { } @Override - public BuildsResponse queryBuildsFor(String repoSlug) { - var encodedSlug = URLEncoder.encode(repoSlug, StandardCharsets.UTF_8); - var repositoryBuildsQuery = "/repo/" - + encodedSlug - + "/builds?limit=1&branch.name=master&include=build.commit"; - var result = queryForResponse(repositoryBuildsQuery, BuildsResponse.class); + public T execute(Query query) { + var result = execute(query.request(), query.responseType()); return result; } - @Override - public RepositoriesResponse queryRepositoriesFor(String owner) { - var encodedOwner = URLEncoder.encode(owner, StandardCharsets.UTF_8); - var ownerRepositoriesQuery = "/owner/" + encodedOwner + "/repos"; - var result = queryForResponse(ownerRepositoriesQuery, RepositoriesResponse.class); - return result; - } - - private T queryForResponse(String query, Class responseType) { - var request = apiRequest(query, apiToken); + private T execute(String request, Class responseType) { + var apiRequest = apiRequest(request, apiToken); try { - var result = CLIENT.send(request, jsonBodyHandler(responseType)); + var result = CLIENT.send(apiRequest, jsonBodyHandler(responseType)); return result.body(); } catch (IOException | InterruptedException e) { - var message = format("Unable to query data for response of type '%s' using query '%s'.", - responseType, query); + var message = format( + "Unable to query data for response of type '%s' using request '%s'.", + responseType, request); throw new RuntimeException(message, e); } } - private static HttpRequest apiRequest(String apiPath, String token) { + private static HttpRequest apiRequest(String request, String token) { return authorizedApiRequest(token) - .uri(URI.create(BASE_URL + apiPath)) + .uri(URI.create(BASE_URL + request)) .build(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java index 907095b6..2d5bb665 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java @@ -20,9 +20,6 @@ package io.spine.chatbot.api.travis; -import io.spine.chatbot.travis.BuildsResponse; -import io.spine.chatbot.travis.RepositoriesResponse; - /** * A Travis CI API client. * @@ -31,12 +28,13 @@ public interface TravisClient { /** - * Queries Travis CI build statuses for a repository determined by the supplied repository slug. - */ - BuildsResponse queryBuildsFor(String repoSlug); - - /** - * Queries Travis CI repositories information for a specified {@code owner}. + * Executes supplied {@code query} and returns response of type {@code T}. + * + * @param query + * query to execute + * @param + * type of the query response + * @return query execution result */ - RepositoriesResponse queryRepositoriesFor(String owner); + T execute(Query query); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java new file mode 100644 index 00000000..190339b2 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api.travis; + +import com.google.protobuf.Message; + +/** + * Travis CI API response marker. + */ +public interface TravisResponse extends Message { + +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index ef22bf77..34a297ca 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -24,6 +24,9 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; +import io.spine.chatbot.api.travis.Build; +import io.spine.chatbot.api.travis.BuildsQuery; +import io.spine.chatbot.api.travis.Commit; import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; @@ -34,8 +37,6 @@ import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildStable; -import io.spine.chatbot.travis.Build; -import io.spine.chatbot.travis.Commit; import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; @@ -81,7 +82,7 @@ final class RepoBuildProcess */ @Assign EitherOf3 handle(CheckRepositoryBuild c) { - var builds = travisClient.queryBuildsFor(id().getValue()) + var builds = travisClient.execute(BuildsQuery.forRepo(id().getValue())) .getBuildsList(); if (builds.isEmpty()) { //TODO:2020-06-19:yuri-sergiichuk: replace with `NoBuildsFound` rejection after migration diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 5cf1df4b..85a8cd14 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -24,13 +24,14 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; +import io.spine.chatbot.api.travis.ReposQuery; +import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.google.chat.event.SpaceRegistered; -import io.spine.chatbot.travis.Repository; import io.spine.core.External; import io.spine.logging.Logging; import io.spine.server.command.Command; @@ -80,7 +81,7 @@ Iterable on(@External SpaceRegistered e) { var spaceId = e.getId(); var commands = ImmutableSet.builder(); commands.add(registerOrgCommand(SPINE_ORGANIZATION, spaceId.getValue())); - travisClient.queryRepositoriesFor(SPINE_ORG) + travisClient.execute(ReposQuery.forOwner(SPINE_ORG)) .getRepositoriesList() .stream() .filter(repository -> WATCHED_REPOS.contains(repository.getName())) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 0714ef77..dc7abeab 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -25,8 +25,8 @@ package spine.chatbot.travis; import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; -option java_package = "io.spine.chatbot.travis"; -option java_outer_classname = "TravisCiProto"; +option java_package = "io.spine.chatbot.api.travis"; +option java_outer_classname = "TravisCiApiProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; @@ -138,6 +138,8 @@ message Build { // A Travis `builds` API endpoint response. message BuildsResponse { + option (is).java_type = "TravisResponse"; + // Builds fetched by the API call. repeated Build builds = 1; } @@ -145,6 +147,8 @@ message BuildsResponse { // A travis `repos` API endpoint response. message RepositoriesResponse { + option (is).java_type = "TravisResponse"; + // Repositories fetched by the API call. repeated Repository repositories = 1; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java index 9a9a37d6..303c9d21 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java @@ -21,21 +21,19 @@ package io.spine.chatbot.api.travis; import io.spine.chatbot.api.FailFastClient; -import io.spine.chatbot.travis.BuildsResponse; -import io.spine.chatbot.travis.RepositoriesResponse; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.protobuf.Messages.defaultInstance; /** * An in-memory test-only implementation of the Travis CI API client. */ public final class InMemoryTravisClient extends FailFastClient implements TravisClient { - private final Map buildsResponses = new ConcurrentHashMap<>(); - private final Map repositoriesResponses = new ConcurrentHashMap<>(); + private final Map, TravisResponse> responses = new ConcurrentHashMap<>(); private InMemoryTravisClient(boolean failFast) { super(failFast); @@ -56,19 +54,12 @@ public static InMemoryTravisClient lenientClient() { } @Override - public BuildsResponse queryBuildsFor(String repoSlug) { - checkNotNull(repoSlug); - var stubbedValue = buildsResponses.get(repoSlug); - var result = failOrDefault(stubbedValue, repoSlug, BuildsResponse.getDefaultInstance()); - return result; - } - - @Override - public RepositoriesResponse queryRepositoriesFor(String owner) { - checkNotNull(owner); - var stubbedValue = repositoriesResponses.get(owner); - var result = failOrDefault(stubbedValue, owner, RepositoriesResponse.getDefaultInstance()); - return result; + public T execute(Query query) { + checkNotNull(query); + var stubbedValue = responses.get(query); + var responseType = query.responseType(); + var result = failOrDefault(stubbedValue, query, defaultInstance(responseType)); + return responseType.cast(result); } /** @@ -77,7 +68,7 @@ public RepositoriesResponse queryRepositoriesFor(String owner) { public void setBuildsFor(String repoSlug, BuildsResponse builds) { checkNotNull(repoSlug); checkNotNull(builds); - buildsResponses.put(repoSlug, builds); + responses.put(BuildsQuery.forRepo(repoSlug), builds); } /** @@ -86,14 +77,13 @@ public void setBuildsFor(String repoSlug, BuildsResponse builds) { public void setRepositoriesFor(String owner, RepositoriesResponse repositories) { checkNotNull(owner); checkNotNull(repositories); - repositoriesResponses.put(owner, repositories); + responses.put(ReposQuery.forOwner(owner), repositories); } /** * Resets state of the configured responses. */ public void reset() { - buildsResponses.clear(); - repositoriesResponses.clear(); + responses.clear(); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index a78978a3..70d2b4e3 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -20,6 +20,10 @@ package io.spine.chatbot.server.github; +import io.spine.chatbot.api.travis.Build; +import io.spine.chatbot.api.travis.BuildsResponse; +import io.spine.chatbot.api.travis.Commit; +import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; @@ -28,10 +32,6 @@ import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildStable; -import io.spine.chatbot.travis.Build; -import io.spine.chatbot.travis.BuildsResponse; -import io.spine.chatbot.travis.Commit; -import io.spine.chatbot.travis.Repository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 2a379c36..03dc63b2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -20,12 +20,12 @@ package io.spine.chatbot.server.github; +import io.spine.chatbot.api.travis.RepositoriesResponse; +import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; -import io.spine.chatbot.travis.RepositoriesResponse; -import io.spine.chatbot.travis.Repository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; From c8a0dfb018ddfaf118b5e2ea0ea805e5c48644f9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 01:05:56 +0300 Subject: [PATCH 208/492] Add equals & hashCode --- .../io/spine/chatbot/api/travis/Query.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java index 2b958aa7..e1d6a3e9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java @@ -20,6 +20,9 @@ package io.spine.chatbot.api.travis; +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; + import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -65,4 +68,31 @@ Class responseType() { static String encode(String value) { return URLEncoder.encode(value, StandardCharsets.UTF_8); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Query)) { + return false; + } + Query query = (Query) o; + return Objects.equal(responseType, query.responseType) && + Objects.equal(request, query.request); + } + + @Override + public int hashCode() { + return Objects.hashCode(responseType, request); + } + + @Override + public String toString() { + return MoreObjects + .toStringHelper(this) + .add("request", request) + .add("responseType", responseType) + .toString(); + } } From a82523c773756943086a53dc97511ea4a3bf2ea9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 01:07:44 +0300 Subject: [PATCH 209/492] Fix thread resource name --- .../spine/chatbot/server/google/chat/ThreadChatProcessTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 3827e84a..690bf87f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -86,7 +86,7 @@ private abstract static class BuildStateChanged extends GoogleChatEntityTest { private final String googleChatSpace = "spaces/1241pjwqe"; private final SpaceId spaceId = spaceIdOf(googleChatSpace); private final String buildNumber = "551"; - private final Thread newThread = new Thread().setName("spaces/1241pjwqe/thread/k12d1o2r1"); + private final Thread newThread = new Thread().setName("spaces/1241pjwqe/threads/k12d1o2r1"); private final Message sentMessage = new Message() .setName("spaces/1241pjwqe/messages/12154363643624") .setThread(newThread); From 9626e8821e2c7d6abcd26eaaf0c1ffa60b440693 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 01:14:01 +0300 Subject: [PATCH 210/492] Fix misprint. `isInitialized` determines whether the message was initialized or not. --- .../io/spine/chatbot/server/github/SpineOrgInitProcess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 85a8cd14..280c1ac9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -75,7 +75,7 @@ final class SpineOrgInitProcess */ @Command Iterable on(@External SpaceRegistered e) { - if (state().isInitialized()) { + if (state().getInitialized()) { return ImmutableSet.of(); } var spaceId = e.getId(); From 91d8164289457fc08c1aa601f8c10746d43a9b02 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 01:33:51 +0300 Subject: [PATCH 211/492] Resolve rejection-related TODOs. throw a rejection if there's no repo builds info. --- .../server/github/RepoBuildProcess.java | 18 ++++++++++++------ ...roto1 => repository_build_rejections.proto} | 4 ---- .../server/github/RepoBuildProcessTest.java | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) rename google-chat-bot/src/main/proto/spine/chatbot/github/{repository_build_rejections.proto1 => repository_build_rejections.proto} (92%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 34a297ca..a522a69e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -37,6 +37,7 @@ import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildStable; +import io.spine.chatbot.github.repository.build.rejection.NoBuildsFound; import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; @@ -64,6 +65,8 @@ * {@code passing} previously. * * + * Or, if the repository builds could not be retrieved, throws {@link NoBuildsFound} rejection. + * *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered * {@link #FAILED_STATUSES failed statuses}. */ @@ -79,17 +82,20 @@ final class RepoBuildProcess /** * Checks the repository build state and propagates the respective events. + * + *

If the repository build state could not be retrieved, + * throws {@link NoBuildsFound} rejection. */ @Assign - EitherOf3 handle(CheckRepositoryBuild c) { + EitherOf3 handle(CheckRepositoryBuild c) + throws NoBuildsFound { var builds = travisClient.execute(BuildsQuery.forRepo(id().getValue())) .getBuildsList(); if (builds.isEmpty()) { - //TODO:2020-06-19:yuri-sergiichuk: replace with `NoBuildsFound` rejection after migration - // to the new java11-compatible Bootstrap version - throw newIllegalStateException( - "No build found for the repository `%s`.", id().getValue() - ); + throw NoBuildsFound + .newBuilder() + .setId(c.getId()) + .build(); } var build = builds.get(0); var buildState = buildStateFrom(build); diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto similarity index 92% rename from google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 rename to google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto index 34b100d7..41e3337c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto1 +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto @@ -31,12 +31,8 @@ option java_generate_equals_and_hash = true; option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; - import "spine/chatbot/github/identifiers.proto"; -//TODO:2020-06-19:yuri-sergiichuk: rename file back to `.proto` after migration -// to the new java11-compatible Bootstrap version - // No CI builds found for the repository. message NoBuildsFound { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 70d2b4e3..af1d2283 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -32,6 +32,7 @@ import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildStable; +import io.spine.chatbot.github.repository.build.rejection.RepositoryBuildRejections; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -45,6 +46,23 @@ final class RepoBuildProcessTest extends GitHubEntityTest { private static final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/web"); + @Test + @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") + void throwNoBuildsFoundRejection() { + travisClient.setBuildsFor(repositoryId.getValue(), BuildsResponse.getDefaultInstance()); + var checkRepoBuild = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().receivesCommand(checkRepoBuild); + + var noBuildsFound = RepositoryBuildRejections.NoBuildsFound + .newBuilder() + .setId(repositoryId) + .vBuild(); + context().assertEvent(noBuildsFound); + } + @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes @Nested @DisplayName("handle build failure") From 4fe74d64404ea158bb4dc57bcdf850411e1213b8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 13:13:32 +0300 Subject: [PATCH 212/492] Image is tagged by JIB already --- cloudbuild.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 7c1bf4c0..972ef7d0 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -18,7 +18,3 @@ steps: timeout: 1200s substitutions: _SERVICE_NAME: "chat-bot-server" - -images: [ - 'gcr.io/${PROJECT_ID}/${_SERVICE_NAME}:latest' -] From 5c641a3337c50187400f453281dc16519e0cd381 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 13:13:50 +0300 Subject: [PATCH 213/492] Tag image explicitly --- google-chat-bot/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/google-chat-bot/build.gradle.kts b/google-chat-bot/build.gradle.kts index 623da7f7..20df7b02 100644 --- a/google-chat-bot/build.gradle.kts +++ b/google-chat-bot/build.gradle.kts @@ -73,6 +73,7 @@ application { jib { to { image = "gcr.io/${gcpProject}/chat-bot-server" + tags = setOf("latest") } container { mainClass = application.mainClassName From 6df9ea5fcf5f772a7d646b6785090ba958ce7497 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 13:15:05 +0300 Subject: [PATCH 214/492] Remove obsolete TODO. Build is working fine with Java11 and bootstrap plugin v1.5.23 --- cloudbuild.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 972ef7d0..044a50cf 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,6 +1,3 @@ -# TODO:2020-06-17:yuri-sergiichuk: the build fails in the cloud with -# java.lang.NoClassDefFoundError: javax/annotation/Generated inside Spine protoc plugin - steps: - name: 'gradle:6.4.1-jdk11' entrypoint: 'gradle' From bab17ffab94d67445b0d9f00ca9b40fa8f0a819b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 15:25:28 +0300 Subject: [PATCH 215/492] Move incoming events controller logic to the IncomingEventsHandler and use ThirdPartyContext for emitting ChatEvent --- .../chatbot/IncomingEventsController.java | 50 +++------- .../spine/chatbot/RepositoriesController.java | 6 +- ...otClient.java => ChatBotServerClient.java} | 11 +-- .../server/google/chat/GoogleChatContext.java | 7 +- .../google/chat/IncomingEventsHandler.java | 98 +++++++++++++++++++ .../server/google/chat/SpaceAggregate.java | 23 +++++ .../server/google/chat/SpaceRepository.java | 40 ++++++++ ...ository.java => ThreadChatRepository.java} | 5 +- ...eRepository.java => ThreadRepository.java} | 2 +- .../server/google/chat/ThreadResources.java | 2 +- .../chat/incoming/incoming_chat_events.proto | 44 +++++++++ .../incoming/incoming_chat_messages.proto | 2 + 12 files changed, 238 insertions(+), 52 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/client/{ChatBotClient.java => ChatBotServerClient.java} (93%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java rename google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/{ThreadChatProcessRepository.java => ThreadChatRepository.java} (93%) rename google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/{ThreadAggregateRepository.java => ThreadRepository.java} (94%) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 37f9ea14..9ab5ead4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -25,20 +25,18 @@ import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; -import io.spine.chatbot.client.ChatBotClient; -import io.spine.chatbot.google.chat.command.RegisterSpace; -import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.google.chat.incoming.ChatEvent; -import io.spine.chatbot.google.chat.incoming.Space; -import io.spine.chatbot.google.chat.incoming.SpaceType; -import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; +import io.spine.chatbot.google.chat.incoming.User; +import io.spine.core.UserId; import io.spine.json.Json; import io.spine.logging.Logging; +import io.spine.server.integration.ThirdPartyContext; import java.nio.charset.StandardCharsets; import java.util.Base64; import static io.micronaut.http.MediaType.APPLICATION_JSON; +import static io.spine.util.Exceptions.newIllegalStateException; /** * A REST controller for handling incoming events from Google Chat. @@ -46,6 +44,8 @@ @Controller("/chat") final class IncomingEventsController implements Logging { + private static final String CONTEXT_NAME = "IncomingChatEvents"; + /** * Processes an incoming Google Chat event. * @@ -57,39 +57,19 @@ String on(@Body PubsubPushNotification pushNotification) { var chatEventJson = decodeBase64Json(message.getData()); _debug().log("Received a new chat event: %s", chatEventJson); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); - var client = ChatBotClient.inProcessClient(Application.SERVER_NAME); - switch (chatEvent.getType()) { - case MESSAGE: - _info().log("Processing user message."); - break; - case ADDED_TO_SPACE: - var space = chatEvent.getSpace(); - _info().log("Bot added to space `%s` (%s).", - space.getDisplayName(), space.getName()); - onBotAddedToSpace(space, client); - break; - case REMOVED_FROM_SPACE: - case CARD_CLICKED: - case UNRECOGNIZED: - case ET_UNKNOWN: - _debug().log("Unsupported chat event type received: %s", chatEvent.getType()); - break; + var actor = eventActor(chatEvent.getUser()); + try (ThirdPartyContext incomingEvents = ThirdPartyContext.singleTenant(CONTEXT_NAME)) { + incomingEvents.emittedEvent(chatEvent, actor); + } catch (Exception e) { + throw newIllegalStateException("Unable to handle incoming Google Chat event.", e); } return "OK"; } - private static void onBotAddedToSpace(Space space, ChatBotClient client) { - var registerSpace = RegisterSpace - .newBuilder() - .setDisplayName(space.getDisplayName()) - .setThreaded(isThreaded(space)) - .setId(GoogleChatIdentifier.spaceIdOf(space.getName())) - .vBuild(); - client.post(registerSpace, SpaceRegistered.class); - } - - private static boolean isThreaded(Space space) { - return space.getType() == SpaceType.ROOM; + private static UserId eventActor(User user) { + return UserId.newBuilder() + .setValue(user.getName()) + .vBuild(); } private static String decodeBase64Json(ByteString encoded) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 2b0d37a5..fc08c266 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -22,7 +22,7 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; -import io.spine.chatbot.client.ChatBotClient; +import io.spine.chatbot.client.ChatBotServerClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.logging.Logging; @@ -42,13 +42,13 @@ final class RepositoriesController implements Logging { @Post("/builds/check") String checkBuildStatuses() { _debug().log("Checking repositories build statues."); - var botClient = ChatBotClient.inProcessClient(SERVER_NAME); + var botClient = ChatBotServerClient.inProcessClient(SERVER_NAME); botClient.listRepositories() .forEach(repository -> checkBuildStatus(botClient, repository)); return "success"; } - private void checkBuildStatus(ChatBotClient botClient, RepositoryId repository) { + private void checkBuildStatus(ChatBotServerClient botClient, RepositoryId repository) { _info().log("Sending `CheckRepositoryBuild` command for repository `%s`", repository.getValue()); var checkRepositoryBuild = checkRepoBuildCommand(repository); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java similarity index 93% rename from google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java index 09a9617e..99a5e0e7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java @@ -42,22 +42,22 @@ * *

Abstracts working with Spine's {@link Client client}. */ -public final class ChatBotClient { +public final class ChatBotServerClient { private final Client client; - private ChatBotClient(Client client) { + private ChatBotServerClient(Client client) { this.client = client; } /** * Creates a new in-process client configured for the specified server. */ - public static ChatBotClient inProcessClient(String serverName) { + public static ChatBotServerClient inProcessClient(String serverName) { Client client = Client .inProcess(serverName) .build(); - return new ChatBotClient(client); + return new ChatBotServerClient(client); } /** @@ -103,8 +103,7 @@ public ImmutableList listRepositories() { /** * Posts a command and waits synchronously till the expected outcome event is published. */ - public void - post(CommandMessage command, Class expectedOutcome) { + public void post(CommandMessage command, Class expectedOutcome) { post(command, expectedOutcome, 1); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index c55683f3..e71383d9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -55,9 +55,10 @@ public BoundedContextBuilder contextBuilder() { configureContextBuilder(GoogleChatClient googleChatClient) { return BoundedContext .singleTenant(GOOGLE_CHAT_CONTEXT_NAME) - .add(SpaceAggregate.class) - .add(new ThreadAggregateRepository()) - .add(new ThreadChatProcessRepository(googleChatClient)); + .add(new SpaceRepository()) + .add(new ThreadRepository()) + .add(new ThreadChatRepository(googleChatClient)) + .addEventDispatcher(new IncomingEventsHandler()); } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java new file mode 100644 index 00000000..8f635fa3 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -0,0 +1,98 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.incoming.ChatEvent; +import io.spine.chatbot.google.chat.incoming.event.AddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.MessageReceived; +import io.spine.chatbot.google.chat.incoming.event.RemovedFromSpace; +import io.spine.core.External; +import io.spine.logging.Logging; +import io.spine.server.event.AbstractEventReactor; +import io.spine.server.event.React; +import io.spine.server.model.Nothing; +import io.spine.server.tuple.EitherOf4; + +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; + +/** + * Google Chat incoming events reactor. + * + *

Processes {@link ChatEvent}s received by the ChatBot. + */ +final class IncomingEventsHandler extends AbstractEventReactor implements Logging { + + /** + * Processes incoming {@link ChatEvent} message and emits one of the following domain events: + * + *

    + *
  • {@link AddedToSpace} — the ChatBot is added to a Google Chat space; + *
  • {@link RemovedFromSpace} — the ChatBot is removed from the Google Chat space; + *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user within a Google Chat space; + *
+ * + *

If the bot receives a chat event with a not supported currently event type, + * {@link Nothing} is emitted. + */ + @React + EitherOf4 + on(@External ChatEvent chatEvent) { + switch (chatEvent.getType()) { + case MESSAGE: + _info().log("New user message received."); + var message = chatEvent.getMessage(); + var messageId = GoogleChatIdentifier.messageIdOf(message.getName()); + var messageReceived = MessageReceived + .newBuilder() + .setEvent(chatEvent) + .setMessageId(messageId) + .vBuild(); + return EitherOf4.withC(messageReceived); + case ADDED_TO_SPACE: + var toSpace = chatEvent.getSpace(); + _info().log("ChatBot added to space `%s` (%s).", + toSpace.getDisplayName(), toSpace.getName()); + var addedToSpace = AddedToSpace + .newBuilder() + .setEvent(chatEvent) + .setSpaceId(spaceIdOf(toSpace.getName())) + .vBuild(); + return EitherOf4.withA(addedToSpace); + case REMOVED_FROM_SPACE: + var fromSpace = chatEvent.getSpace(); + _info().log("ChatBot removed from space `%s` (%s).", + fromSpace.getDisplayName(), fromSpace.getName()); + var removedFromSpace = RemovedFromSpace + .newBuilder() + .setEvent(chatEvent) + .setSpaceId(spaceIdOf(fromSpace.getName())) + .vBuild(); + return EitherOf4.withB(removedFromSpace); + + case CARD_CLICKED: + case UNRECOGNIZED: + case ET_UNKNOWN: + default: + _debug().log("Unsupported chat event type received: %s", chatEvent.getType()); + return EitherOf4.withD(nothing()); + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 29b1da47..be5e1950 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -24,10 +24,14 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.google.chat.incoming.SpaceType; +import io.spine.chatbot.google.chat.incoming.event.AddedToSpace; +import io.spine.core.External; import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; +import io.spine.server.command.Command; /** * A room or direct message chat in the Google Chat. @@ -36,6 +40,21 @@ */ final class SpaceAggregate extends Aggregate implements Logging { + /** + * Registers a new space when the ChatBot is added to the space. + */ + @Command + RegisterSpace on(@External AddedToSpace e) { + var space = e.getEvent() + .getSpace(); + return RegisterSpace + .newBuilder() + .setDisplayName(space.getDisplayName()) + .setThreaded(isThreaded(space)) + .setId(e.getSpaceId()) + .vBuild(); + } + /** * Registers the space in the context. */ @@ -58,4 +77,8 @@ private void on(SpaceRegistered e) { .setSingleUserBotDm(e.getSingleUserBotDm()) .setThreaded(e.getThreaded()); } + + private static boolean isThreaded(io.spine.chatbot.google.chat.incoming.Space space) { + return space.getType() == SpaceType.ROOM; + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java new file mode 100644 index 00000000..0647149e --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java @@ -0,0 +1,40 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.incoming.event.AddedToSpace; +import io.spine.server.aggregate.AggregateRepository; +import io.spine.server.route.EventRouting; + +import static io.spine.server.route.EventRoute.withId; + +/** + * The repository for {@link SpaceAggregate}s. + */ +final class SpaceRepository extends AggregateRepository { + + @Override + protected void setupEventRouting(EventRouting routing) { + super.setupEventRouting(routing); + routing.route(AddedToSpace.class, (event, context) -> withId(event.getSpaceId())); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java similarity index 93% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 9af30771..997db33d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcessRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -40,12 +40,11 @@ /** * The repository for {@link ThreadChatProcess}es. */ -final class ThreadChatProcessRepository - extends ProcessManagerRepository { +final class ThreadChatRepository extends ProcessManagerRepository { private final GoogleChatClient googleChatClient; - ThreadChatProcessRepository(GoogleChatClient googleChatClient) { + ThreadChatRepository(GoogleChatClient googleChatClient) { this.googleChatClient = googleChatClient; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java similarity index 94% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java index 7507adc9..12696ed6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregateRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java @@ -31,7 +31,7 @@ /** * The repository for {@link ThreadAggregate}s. */ -final class ThreadAggregateRepository extends AggregateRepository { +final class ThreadRepository extends AggregateRepository { @Override protected void setupEventRouting(EventRouting routing) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java index 3d438603..4f604b64 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -25,7 +25,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** - * An utility for working with {@link ThreadResource}s. + * A utility for working with {@link ThreadResource}s. */ public final class ThreadResources { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto new file mode 100644 index 00000000..5cf8f321 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package spine.chatbot.google.chat.incoming; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat.incoming.event"; +option java_outer_classname = "IncomingChatEventsProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; + +import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/incoming/incoming_chat_messages.proto"; + +// The ChatBot is added to a Google Chat space. +message AddedToSpace { + + // The ID of the Space to which the ChatBot is added. + SpaceId space_id = 1 [(required) = true]; + + // The actual chat event message. + ChatEvent event = 2; +} + +// The ChatBot is removed from the Google Chat space. +message RemovedFromSpace { + + // The ID of the Space from which the ChatBot is removed. + SpaceId space_id = 1 [(required) = true]; + + // The actual chat event message. + ChatEvent event = 2; +} + +// The ChatBot received a new incoming Google Chat message. +message MessageReceived { + + // The ID of the new message. + MessageId message_id = 1 [(required) = true]; + + // The actual chat event message. + ChatEvent event = 2; +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 0dab6433..acde5031 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -33,6 +33,8 @@ option java_generate_equals_and_hash = true; // A Google Chat incoming event. message ChatEvent { + option (is).java_type = "io.spine.base.EventMessage"; + // type of the event EventType type = 1 [(required) = true]; From f567e41c90ed6e1dee7b7d2347fdac89b130c465 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 15:27:37 +0300 Subject: [PATCH 216/492] Add `Bot` prefix to bot-specific events --- .../server/google/chat/IncomingEventsHandler.java | 14 +++++++------- .../chatbot/server/google/chat/SpaceAggregate.java | 4 ++-- .../server/google/chat/SpaceRepository.java | 4 ++-- .../chat/incoming/incoming_chat_events.proto | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 8f635fa3..4d4c1589 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -21,9 +21,9 @@ package io.spine.chatbot.server.google.chat; import io.spine.chatbot.google.chat.incoming.ChatEvent; -import io.spine.chatbot.google.chat.incoming.event.AddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.BotRemovedFromSpace; import io.spine.chatbot.google.chat.incoming.event.MessageReceived; -import io.spine.chatbot.google.chat.incoming.event.RemovedFromSpace; import io.spine.core.External; import io.spine.logging.Logging; import io.spine.server.event.AbstractEventReactor; @@ -44,8 +44,8 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin * Processes incoming {@link ChatEvent} message and emits one of the following domain events: * *

    - *
  • {@link AddedToSpace} — the ChatBot is added to a Google Chat space; - *
  • {@link RemovedFromSpace} — the ChatBot is removed from the Google Chat space; + *
  • {@link BotAddedToSpace} — the ChatBot is added to a Google Chat space; + *
  • {@link BotRemovedFromSpace} — the ChatBot is removed from the Google Chat space; *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user within a Google Chat space; *
* @@ -53,7 +53,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin * {@link Nothing} is emitted. */ @React - EitherOf4 + EitherOf4 on(@External ChatEvent chatEvent) { switch (chatEvent.getType()) { case MESSAGE: @@ -70,7 +70,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin var toSpace = chatEvent.getSpace(); _info().log("ChatBot added to space `%s` (%s).", toSpace.getDisplayName(), toSpace.getName()); - var addedToSpace = AddedToSpace + var addedToSpace = BotAddedToSpace .newBuilder() .setEvent(chatEvent) .setSpaceId(spaceIdOf(toSpace.getName())) @@ -80,7 +80,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin var fromSpace = chatEvent.getSpace(); _info().log("ChatBot removed from space `%s` (%s).", fromSpace.getDisplayName(), fromSpace.getName()); - var removedFromSpace = RemovedFromSpace + var removedFromSpace = BotRemovedFromSpace .newBuilder() .setEvent(chatEvent) .setSpaceId(spaceIdOf(fromSpace.getName())) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index be5e1950..8724fef2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -25,7 +25,7 @@ import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.google.chat.incoming.SpaceType; -import io.spine.chatbot.google.chat.incoming.event.AddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import io.spine.core.External; import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; @@ -44,7 +44,7 @@ final class SpaceAggregate extends Aggregate impl * Registers a new space when the ChatBot is added to the space. */ @Command - RegisterSpace on(@External AddedToSpace e) { + RegisterSpace on(@External BotAddedToSpace e) { var space = e.getEvent() .getSpace(); return RegisterSpace diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java index 0647149e..5fba4ab4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.google.chat; import io.spine.chatbot.google.chat.SpaceId; -import io.spine.chatbot.google.chat.incoming.event.AddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import io.spine.server.aggregate.AggregateRepository; import io.spine.server.route.EventRouting; @@ -35,6 +35,6 @@ final class SpaceRepository extends AggregateRepository @Override protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); - routing.route(AddedToSpace.class, (event, context) -> withId(event.getSpaceId())); + routing.route(BotAddedToSpace.class, (event, context) -> withId(event.getSpaceId())); } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto index 5cf8f321..90f00e7a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto @@ -14,7 +14,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/incoming/incoming_chat_messages.proto"; // The ChatBot is added to a Google Chat space. -message AddedToSpace { +message BotAddedToSpace { // The ID of the Space to which the ChatBot is added. SpaceId space_id = 1 [(required) = true]; @@ -24,7 +24,7 @@ message AddedToSpace { } // The ChatBot is removed from the Google Chat space. -message RemovedFromSpace { +message BotRemovedFromSpace { // The ID of the Space from which the ChatBot is removed. SpaceId space_id = 1 [(required) = true]; From 35713e8230009a59be6fd3cdfbb24c2371afeff3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 15:52:41 +0300 Subject: [PATCH 217/492] Emit SpaceRegistered event as reaction on the BotAddedToSpace event. --- .../server/google/chat/SpaceAggregate.java | 8 +-- .../google/chat/SpaceAggregateTest.java | 70 ++++++++++++++++++- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 8724fef2..60d3397c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -31,7 +31,7 @@ import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; import io.spine.server.command.Assign; -import io.spine.server.command.Command; +import io.spine.server.event.React; /** * A room or direct message chat in the Google Chat. @@ -43,11 +43,11 @@ final class SpaceAggregate extends Aggregate impl /** * Registers a new space when the ChatBot is added to the space. */ - @Command - RegisterSpace on(@External BotAddedToSpace e) { + @React + SpaceRegistered on(@External BotAddedToSpace e) { var space = e.getEvent() .getSpace(); - return RegisterSpace + return SpaceRegistered .newBuilder() .setDisplayName(space.getDisplayName()) .setThreaded(isThreaded(space)) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index cdf5113f..cbd49ec0 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -24,21 +24,28 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.google.chat.incoming.ChatEvent; +import io.spine.chatbot.google.chat.incoming.EventType; +import io.spine.chatbot.google.chat.incoming.SpaceType; +import io.spine.chatbot.google.chat.incoming.User; +import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; + @DisplayName("SpaceAggregate should") final class SpaceAggregateTest extends GoogleChatEntityTest { + private static final SpaceId spaceId = spaceIdOf("spaces/poqwdpQ21"); + private static final String displayName = "Spine Developers"; + @Nested @DisplayName("register a space") final class Register { - private final SpaceId spaceId = GoogleChatIdentifier.spaceIdOf("spaces/poqwdpQ21"); - private final String displayName = "Spine Developers"; - @BeforeEach void setUp() { var registerSpace = RegisterSpace @@ -75,4 +82,61 @@ void settingState() { .isEqualTo(expectedState); } } + + @Nested + @DisplayName("register a space when a bot is added to the space") + final class RegisterDirectly { + + @BeforeEach + void setUp() { + var chatEvent = ChatEvent + .newBuilder() + .setSpace(chatSpace()) + .setUser(User.newBuilder() + .setName("Lukas")) + .setType(EventType.ADDED_TO_SPACE) + .setEventTime("2020-06-19T15:39:01Z") + .vBuild(); + var botAddedToSpace = BotAddedToSpace + .newBuilder() + .setSpaceId(spaceId) + .setEvent(chatEvent) + .vBuild(); + context().receivesExternalEvent(botAddedToSpace); + } + + @Test + @DisplayName("producing SpaceRegistered event") + void producingEvent() { + var spaceRegistered = SpaceRegistered + .newBuilder() + .setId(spaceId) + .setDisplayName(displayName) + .setThreaded(true) + .vBuild(); + context().assertEvent(spaceRegistered); + } + + @Test + @DisplayName("setting Space state") + void settingState() { + var expectedState = Space + .newBuilder() + .setId(spaceId) + .setThreaded(true) + .setDisplayName(displayName) + .vBuild(); + context().assertState(spaceId, Space.class) + .isEqualTo(expectedState); + } + + private io.spine.chatbot.google.chat.incoming.Space chatSpace() { + return io.spine.chatbot.google.chat.incoming.Space + .newBuilder() + .setName(spaceId.getValue()) + .setDisplayName(displayName) + .setType(SpaceType.ROOM) + .vBuild(); + } + } } From 279b04c1d61f3f27ffc549c1a42a347824b5bae9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:08:03 +0300 Subject: [PATCH 218/492] Rename EntityTest to ContextAwareTest --- ...ityTest.java => GitHubContextAwareTest.java} | 17 ++++++++++++----- .../github/OrganizationAggregateTest.java | 2 +- .../server/github/RepoBuildProcessTest.java | 14 +++++++------- .../server/github/RepositoryAggregateTest.java | 2 +- .../server/github/SpineOrgInitProcessTest.java | 4 ++-- ...est.java => GoogleChatContextAwareTest.java} | 17 ++++++++++++----- .../server/google/chat/SpaceAggregateTest.java | 2 +- .../server/google/chat/ThreadAggregateTest.java | 2 +- .../google/chat/ThreadChatProcessTest.java | 4 ++-- 9 files changed, 39 insertions(+), 25 deletions(-) rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{GitHubEntityTest.java => GitHubContextAwareTest.java} (77%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/{GoogleChatEntityTest.java => GoogleChatContextAwareTest.java} (76%) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java similarity index 77% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java index a4f0fe9e..64a6d57e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubEntityTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java @@ -27,14 +27,14 @@ import org.junit.jupiter.api.AfterEach; /** - * An abstract test-base for GitHub context entity tests. + * An abstract test-base for GitHub context-based tests. */ -class GitHubEntityTest extends ContextAwareTest { +class GitHubContextAwareTest extends ContextAwareTest { - final InMemoryTravisClient travisClient = InMemoryTravisClient.strictClient(); + private final InMemoryTravisClient travisClient = InMemoryTravisClient.strictClient(); @Override - protected BoundedContextBuilder contextBuilder() { + protected final BoundedContextBuilder contextBuilder() { return GitHubContext .newBuilder() .setTravis(travisClient) @@ -45,8 +45,15 @@ protected BoundedContextBuilder contextBuilder() { @AfterEach @OverridingMethodsMustInvokeSuper @Override - protected void closeContext() { + protected final void closeContext() { super.closeContext(); travisClient.reset(); } + + /** + * Returns configured for the {@link #context() context} Travis client. + */ + final InMemoryTravisClient travisClient() { + return travisClient; + } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index a94a5b64..8c330046 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -34,7 +34,7 @@ import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") -final class OrganizationAggregateTest extends GitHubEntityTest { +final class OrganizationAggregateTest extends GitHubContextAwareTest { @Nested @DisplayName("register an organization") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index af1d2283..e91a644f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -42,14 +42,14 @@ import static io.spine.chatbot.server.github.RepoBuildProcess.buildStateFrom; @DisplayName("RepoBuildProcess should") -final class RepoBuildProcessTest extends GitHubEntityTest { +final class RepoBuildProcessTest extends GitHubContextAwareTest { private static final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/web"); @Test @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") void throwNoBuildsFoundRejection() { - travisClient.setBuildsFor(repositoryId.getValue(), BuildsResponse.getDefaultInstance()); + travisClient().setBuildsFor(repositoryId.getValue(), BuildsResponse.getDefaultInstance()); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -73,7 +73,7 @@ final class FailedBuild { @BeforeEach void setUp() { - travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(build)); + travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(build)); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -122,13 +122,13 @@ final class RecoveredBuild { @BeforeEach void setUp() { - travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -178,13 +178,13 @@ final class StableBuild { @BeforeEach void setUp() { - travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient.setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 7f654cf8..1c38fb94 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -36,7 +36,7 @@ import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") -final class RepositoryAggregateTest extends GitHubEntityTest { +final class RepositoryAggregateTest extends GitHubContextAwareTest { @Nested @DisplayName("register a repository") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 03dc63b2..b9077369 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -34,7 +34,7 @@ import static io.spine.chatbot.server.github.SpineOrgInitProcess.SPINE_ORGANIZATION; @DisplayName("SpineOrgInitProcess should") -final class SpineOrgInitProcessTest extends GitHubEntityTest { +final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @Nested @DisplayName("perform initialization of watched spine resources") @@ -54,7 +54,7 @@ void setUp() { .newBuilder() .addRepositories(repository) .vBuild(); - travisClient.setRepositoriesFor(SPINE_ORGANIZATION.getValue(), repositoriesResponse); + travisClient().setRepositoriesFor(SPINE_ORGANIZATION.getValue(), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() .setId(spaceId) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java similarity index 76% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java index fd500e2a..60eab080 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatEntityTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java @@ -27,14 +27,14 @@ import org.junit.jupiter.api.AfterEach; /** - * An abstract test-base for Google Chat context entity tests. + * An abstract test-base for Google Chat context-based tests. */ -class GoogleChatEntityTest extends ContextAwareTest { +class GoogleChatContextAwareTest extends ContextAwareTest { - final InMemoryGoogleChatClient googleChatClient = InMemoryGoogleChatClient.strictClient(); + private final InMemoryGoogleChatClient googleChatClient = InMemoryGoogleChatClient.strictClient(); @Override - protected BoundedContextBuilder contextBuilder() { + protected final BoundedContextBuilder contextBuilder() { return GoogleChatContext .newBuilder() .setGoogleChatClient(googleChatClient) @@ -45,8 +45,15 @@ protected BoundedContextBuilder contextBuilder() { @AfterEach @OverridingMethodsMustInvokeSuper @Override - protected void closeContext() { + protected final void closeContext() { super.closeContext(); googleChatClient.reset(); } + + /** + * Returns configured for the {@link #context() context} Google Chat client. + */ + final InMemoryGoogleChatClient googleChatClient() { + return googleChatClient; + } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index cbd49ec0..9aa9591b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -37,7 +37,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; @DisplayName("SpaceAggregate should") -final class SpaceAggregateTest extends GoogleChatEntityTest { +final class SpaceAggregateTest extends GoogleChatContextAwareTest { private static final SpaceId spaceId = spaceIdOf("spaces/poqwdpQ21"); private static final String displayName = "Spine Developers"; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index be2147a7..f8b726e2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -40,7 +40,7 @@ import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") -final class ThreadAggregateTest extends GoogleChatEntityTest { +final class ThreadAggregateTest extends GoogleChatContextAwareTest { @Nested @DisplayName("initialize a thread") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 690bf87f..48dfcd38 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -79,7 +79,7 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, } } - private abstract static class BuildStateChanged extends GoogleChatEntityTest { + private abstract static class BuildStateChanged extends GoogleChatContextAwareTest { private final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/money"); private final ThreadId threadId = threadIdOf(repositoryId.getValue()); @@ -93,7 +93,7 @@ private abstract static class BuildStateChanged extends GoogleChatEntityTest { @BeforeEach void setUp() { - googleChatClient.setMessageForBuildStatusUpdate(buildNumber, sentMessage); + googleChatClient().setMessageForBuildStatusUpdate(buildNumber, sentMessage); var newBuildState = BuildState .newBuilder() .setGoogleChatSpace(googleChatSpace) From 7a422cac55a07af14c94d1cf5e53ffbdcf7a717a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:20:30 +0300 Subject: [PATCH 219/492] Add IncomingEvents handler test --- .../google/chat/IncomingEventsHandler.java | 3 +- .../chat/IncomingEventsHandlerTest.java | 127 ++++++++++++++++++ .../google/chat/SpaceAggregateTest.java | 2 +- 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 4d4c1589..6bf52c1f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -46,7 +46,8 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin *
    *
  • {@link BotAddedToSpace} — the ChatBot is added to a Google Chat space; *
  • {@link BotRemovedFromSpace} — the ChatBot is removed from the Google Chat space; - *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user within a Google Chat space; + *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user + * within a Google Chat space. *
* *

If the bot receives a chat event with a not supported currently event type, diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java new file mode 100644 index 00000000..51d0d1d0 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -0,0 +1,127 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.MessageId; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.google.chat.incoming.ChatEvent; +import io.spine.chatbot.google.chat.incoming.EventType; +import io.spine.chatbot.google.chat.incoming.Message; +import io.spine.chatbot.google.chat.incoming.SpaceType; +import io.spine.chatbot.google.chat.incoming.User; +import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.BotRemovedFromSpace; +import io.spine.chatbot.google.chat.incoming.event.MessageReceived; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; + +@DisplayName("IncomingEventsHandler should") +final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { + + private static final SpaceId spaceId = spaceIdOf("spaces/fqeq325661a"); + private static final MessageId messageId = messageIdOf("spaces/fqeq325661a/messages/422"); + + @Test + @DisplayName("add bot to a space") + void addBot() { + // given + var chatEvent = chatEventOfType(EventType.ADDED_TO_SPACE); + var botAddedToSpace = BotAddedToSpace + .newBuilder() + .setEvent(chatEvent) + .setSpaceId(spaceId) + .vBuild(); + // when + context().receivesExternalEvent(chatEvent); + // then + context().assertEvent(botAddedToSpace); + } + + @Test + @DisplayName("remove bot from the space") + void removeBot() { + // given + var chatEvent = chatEventOfType(EventType.REMOVED_FROM_SPACE); + var botRemovedFromSpace = BotRemovedFromSpace + .newBuilder() + .setEvent(chatEvent) + .setSpaceId(spaceId) + .vBuild(); + // when + context().receivesExternalEvent(chatEvent); + // then + context().assertEvent(botRemovedFromSpace); + } + + @Test + @DisplayName("receive incoming message") + void receiveIncomingMessage() { + // given + var chatEvent = chatEventOfType(EventType.MESSAGE); + var messageReceived = MessageReceived + .newBuilder() + .setEvent(chatEvent) + .setMessageId(messageId) + .vBuild(); + // when + context().receivesExternalEvent(chatEvent); + // then + context().assertEvent(messageReceived); + } + + private static ChatEvent chatEventOfType(EventType type) { + return ChatEvent + .newBuilder() + .setSpace(chatSpace()) + .setType(type) + .setUser(sender()) + .setEventTime("2020-06-20T15:42:02Z") + .setMessage(chatMessage()) + .vBuild(); + } + + private static Message chatMessage() { + return Message + .newBuilder() + .setName(messageId.getValue()) + .setSender(sender()) + .setText("To be, or not to be, that is the question.") + .vBuild(); + } + + private static User sender() { + return User + .newBuilder() + .setName("users/00qwe123") + .vBuild(); + } + + private static io.spine.chatbot.google.chat.incoming.Space chatSpace() { + return io.spine.chatbot.google.chat.incoming.Space + .newBuilder() + .setName(spaceId.getValue()) + .setType(SpaceType.ROOM) + .vBuild(); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 9aa9591b..74105854 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -93,7 +93,7 @@ void setUp() { .newBuilder() .setSpace(chatSpace()) .setUser(User.newBuilder() - .setName("Lukas")) + .setName("users/12e1ojep1")) .setType(EventType.ADDED_TO_SPACE) .setEventTime("2020-06-19T15:39:01Z") .vBuild(); From 5904e8a46956e80fcd8efc8317376184c2ecbdde Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:32:45 +0300 Subject: [PATCH 220/492] Add note about using local delivery in prod --- .../main/java/io/spine/chatbot/ChatBotServerEnvironment.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index c6a4d455..c6875926 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -57,6 +57,9 @@ static void initializeEnvironment() { var se = ServerEnvironment.instance(); var storageFactory = dsStorageFactory(); se.use(InMemoryTransportFactory.newInstance(), Production.class); + //TODO:2020-06-21:yuri-sergiichuk: switch to io.spine.chatbot.delivery.DistributedDelivery + // for Production environment after implementing the delivery strategy. + // see https://github.com/SpineEventEngine/chat-bot/issues/5. se.use(LocalDelivery.instance, Production.class); se.use(LocalDelivery.instance, Tests.class); se.use(storageFactory, Production.class); From da969bd67c9cc5e53f2c7c56ceb7c0e823452924 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:39:59 +0300 Subject: [PATCH 221/492] Add comment on the server name. --- google-chat-bot/src/main/java/io/spine/chatbot/Application.java | 1 + 1 file changed, 1 insertion(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index ac6e51e6..eb252448 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -43,6 +43,7 @@ **/ public final class Application { + /** Name of the GRPC {@link Server}. **/ static final String SERVER_NAME = "ChatBotServer"; /** From 4d94977c8d4a0a6a8666c5314135552aa33abb77 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:41:35 +0300 Subject: [PATCH 222/492] Add more details to the thrown exception --- .../src/main/java/io/spine/chatbot/Application.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index eb252448..53e44263 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -28,6 +28,8 @@ import java.io.IOException; +import static io.spine.util.Exceptions.newIllegalStateException; + /** * The entry point to the Google Chat Bot application. * @@ -81,8 +83,7 @@ private static void initializeSpine() { * Starts Spine in-process server. */ @VisibleForTesting - static void startSpineServer(GitHubContext gitHubContext, - GoogleChatContext googleChatContext) { + static void startSpineServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { Server server = Server .inProcess(SERVER_NAME) .add(gitHubContext.contextBuilder()) @@ -91,7 +92,9 @@ static void startSpineServer(GitHubContext gitHubContext, try { server.start(); } catch (IOException e) { - throw new RuntimeException(e); + throw newIllegalStateException( + "Unable to start Spine GRPC server `%s`.", SERVER_NAME, e + ); } } } From 21f5adf1b2cde5221bef12e9b56395b9c1ebbe32 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:44:54 +0300 Subject: [PATCH 223/492] Cleanup docs --- .../java/io/spine/chatbot/IncomingEventsController.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 9ab5ead4..263ed405 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -49,7 +49,7 @@ final class IncomingEventsController implements Logging { /** * Processes an incoming Google Chat event. * - *

When a bot is added to a new space, registers the space in the system. + *

Dispatches the event using {@link ThirdPartyContext}. */ @Post(value = "/incoming/event", consumes = APPLICATION_JSON) String on(@Body PubsubPushNotification pushNotification) { @@ -67,9 +67,10 @@ String on(@Body PubsubPushNotification pushNotification) { } private static UserId eventActor(User user) { - return UserId.newBuilder() - .setValue(user.getName()) - .vBuild(); + return UserId + .newBuilder() + .setValue(user.getName()) + .vBuild(); } private static String decodeBase64Json(ByteString encoded) { From 499d4174d1971b4436f3ace133c366bdfe176c3c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 16:47:17 +0300 Subject: [PATCH 224/492] Use proper order of args for `Exceptions` --- google-chat-bot/src/main/java/io/spine/chatbot/Application.java | 2 +- .../main/java/io/spine/chatbot/IncomingEventsController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 53e44263..ad075610 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -93,7 +93,7 @@ static void startSpineServer(GitHubContext gitHubContext, GoogleChatContext goog server.start(); } catch (IOException e) { throw newIllegalStateException( - "Unable to start Spine GRPC server `%s`.", SERVER_NAME, e + e, "Unable to start Spine GRPC server `%s`.", SERVER_NAME ); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 263ed405..e8d82a5c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -61,7 +61,7 @@ String on(@Body PubsubPushNotification pushNotification) { try (ThirdPartyContext incomingEvents = ThirdPartyContext.singleTenant(CONTEXT_NAME)) { incomingEvents.emittedEvent(chatEvent, actor); } catch (Exception e) { - throw newIllegalStateException("Unable to handle incoming Google Chat event.", e); + throw newIllegalStateException(e, "Unable to handle incoming Google Chat event."); } return "OK"; } From 632f088261383317fd9f161d1c216951c60996fd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:10:19 +0300 Subject: [PATCH 225/492] Use different icons for different statuses --- .../api/google/chat/BuildStateUpdates.java | 12 +++++-- .../chatbot/server/github/BuildStates.java | 35 +++++++++++++++++-- .../server/github/RepoBuildProcess.java | 12 ++----- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 6913e5a5..1ccea7d0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -29,6 +29,7 @@ import com.google.common.collect.ImmutableList; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.google.chat.thread.ThreadResource; +import io.spine.chatbot.server.github.BuildStates; import io.spine.protobuf.Messages; import static io.spine.chatbot.api.google.chat.ChatWidgets.cardWith; @@ -42,6 +43,11 @@ */ final class BuildStateUpdates { + private static final String FAILURE_ICON = + "https://storage.googleapis.com/spine-chat-bot.appspot.com/failure-icon.png"; + private static final String SUCCESS_ICON = + "https://storage.googleapis.com/spine-chat-bot.appspot.com/success-icon.png"; + /** * Prevents instantiation of this utility class. */ @@ -49,17 +55,17 @@ private BuildStateUpdates() { } /** - * Creates a new {@link BuildState} update message of of the supplied state and the thread - * name. + * Creates a new {@link BuildState} update message from the supplied state and thread. * *

If the thread has no name set, assumes that the update message should be * sent to a new thread. */ static Message buildStateMessage(BuildState buildState, ThreadResource thread) { checkValid(buildState); + var headerIcon = BuildStates.isFailed(buildState) ? FAILURE_ICON : SUCCESS_ICON; var cardHeader = new CardHeader() .setTitle(buildState.getRepositorySlug()) - .setImageUrl("https://www.freeiconspng.com/uploads/failure-icon-2.png"); + .setImageUrl(headerIcon); var sections = ImmutableList.of( buildStateSection(buildState), commitSection(buildState.getLastCommit()), diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java index 43843102..b701cd7d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java @@ -20,16 +20,21 @@ package io.spine.chatbot.server.github; +import com.google.common.collect.ImmutableSet; import io.spine.chatbot.github.repository.build.BuildState; import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.util.Exceptions.newIllegalArgumentException; /** - * A utility class for working with {@link io.spine.chatbot.github.repository.build.BuildState.State - * BuildState.State}s. + * A utility class for working with {@link BuildState.State}s. */ -final class BuildStates { +public final class BuildStates { + + /** Failed Travis build states. **/ + private static final ImmutableSet FAILED_STATUSES = ImmutableSet.of( + BuildState.State.CANCELLED, BuildState.State.FAILED, BuildState.State.ERRORED + ); /** * Prevents instantiation of this utility class. @@ -51,4 +56,28 @@ static BuildState.State buildStateFrom(String state) { "Unable to create build state out of the supplied string value `%s`.", state ); } + + /** + * Determines whether the build is failed. + * + * @return `true` if the build is failed, `false` otherwise + * @see #isFailed(BuildState.State) + */ + public static boolean isFailed(BuildState buildState) { + checkNotNull(buildState); + return isFailed(buildState.getState()); + } + + /** + * Determines whether the build state denotes a filed status. + * + *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered + * {@link #FAILED_STATUSES failed statuses}. + * + * @return `true` if the build status is failed, `false` otherwise + */ + public static boolean isFailed(BuildState.State state) { + checkNotNull(state); + return FAILED_STATUSES.contains(state); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index a522a69e..401fe660 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -21,7 +21,6 @@ package io.spine.chatbot.server.github; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; import io.spine.chatbot.api.travis.Build; @@ -66,17 +65,10 @@ * * * Or, if the repository builds could not be retrieved, throws {@link NoBuildsFound} rejection. - * - *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered - * {@link #FAILED_STATUSES failed statuses}. */ final class RepoBuildProcess extends ProcessManager { - private static final ImmutableSet FAILED_STATUSES = ImmutableSet.of( - BuildState.State.CANCELLED, BuildState.State.FAILED, BuildState.State.ERRORED - ); - @LazyInit private @MonotonicNonNull TravisClient travisClient; @@ -147,10 +139,10 @@ EitherOf3 handle(CheckRepositoryBuild private static BuildStateStatusChange stateStatusChangeOf(BuildState buildState) { var currentState = buildState.getState(); var previousState = buildState.getPreviousState(); - if (FAILED_STATUSES.contains(currentState)) { + if (BuildStates.isFailed(currentState)) { return FAILED; } - if (currentState == PASSED && FAILED_STATUSES.contains(previousState)) { + if (currentState == PASSED && BuildStates.isFailed(previousState)) { return RECOVERED; } if (currentState == PASSED && previousState == PASSED) { From e786e4b52ef23373eb6850acced2a3715b49a8fd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:16:06 +0300 Subject: [PATCH 226/492] Update action button names --- .../io/spine/chatbot/api/google/chat/BuildStateUpdates.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 1ccea7d0..e8606110 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -94,8 +94,8 @@ private static Section commitSection(BuildState.Commit commit) { private static Section actions(BuildState buildState) { BuildState.Commit commit = buildState.getLastCommit(); WidgetMarkup actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( - linkButton("Open build", buildState.getTravisCiUrl()), - linkButton("Open changeset", commit.getCompareUrl()) + linkButton("Build", buildState.getTravisCiUrl()), + linkButton("Changeset", commit.getCompareUrl()) )); return sectionWithWidget(actionButtons); } From a2044f831afafed2d3212ec046ce4d8807370984 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:24:27 +0300 Subject: [PATCH 227/492] cleanup docs --- .../java/io/spine/chatbot/api/google/chat/ChatWidgets.java | 4 +++- .../java/io/spine/chatbot/api/google/chat/GoogleChat.java | 4 +++- .../main/java/io/spine/chatbot/api/travis/TravisResponse.java | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java index 4311fd5c..62a212f7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java @@ -41,7 +41,9 @@ */ final class ChatWidgets { - /** Prevents instantiation of this utility class. **/ + /** + * Prevents instantiation of this utility class. + */ private ChatWidgets() { } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 8ca4e3c6..a31fcf10 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -53,7 +53,9 @@ private GoogleChat(HangoutsChat chat) { } /** - * Creates Google Chat client. + * Creates a new Google Chat client. + * + *

The client is backed by {@link HangoutsChat} API. */ public static GoogleChatClient instance() { return new GoogleChat(hangoutsChat()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java index 190339b2..276c549e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java @@ -26,5 +26,4 @@ * Travis CI API response marker. */ public interface TravisResponse extends Message { - } From a771e99aab82275bf5289e732901e9bdacd07cdb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:28:39 +0300 Subject: [PATCH 228/492] Add missing EOFs --- .../main/java/io/spine/chatbot/server/github/package-info.java | 2 +- .../java/io/spine/chatbot/server/google/chat/package-info.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java index 1d94b1ab..d2353159 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java @@ -32,4 +32,4 @@ import com.google.errorprone.annotations.CheckReturnValue; import io.spine.core.BoundedContext; -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java index f65d5039..049f4d99 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java @@ -32,4 +32,4 @@ import com.google.errorprone.annotations.CheckReturnValue; import io.spine.core.BoundedContext; -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file +import javax.annotation.ParametersAreNonnullByDefault; From 0a503b3cf558c8c21ddd7cb999ab491b48a3f6ff Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:30:23 +0300 Subject: [PATCH 229/492] Drop extra `.` --- .../main/proto/spine/chatbot/google/chat/thread_events.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index fc8e2f79..9b534cab 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -45,7 +45,7 @@ message ThreadInitialized { SpaceId space_id = 3 [(required) = true]; } -// A message added to the thead.. +// A message added to the thead. message MessageAdded { MessageId id = 1 [(required) = true]; From 12f728c2b41a20617564d6b2a2d538a344ab325c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:31:17 +0300 Subject: [PATCH 230/492] Add missing dots --- .../src/main/proto/spine/chatbot/travis/travis.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index dc7abeab..d2f926ab 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -90,10 +90,10 @@ message Commit { // Commit author. Author author = 7; - // Git commit author information + // Git commit author information. message Author { - // Git name of the commit author + // Git name of the commit author. string name = 1; } } From 20068a51fa0697c11c00bf0f666f0554fbdb3ae8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:32:28 +0300 Subject: [PATCH 231/492] add missing EOF --- google-chat-bot/src/main/resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/resources/log4j2.xml b/google-chat-bot/src/main/resources/log4j2.xml index fb134e31..4bcbb06a 100644 --- a/google-chat-bot/src/main/resources/log4j2.xml +++ b/google-chat-bot/src/main/resources/log4j2.xml @@ -32,4 +32,4 @@ - \ No newline at end of file + From e09c9d09528a6f1fb4c4476a82dc8bb9834afc92 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:35:44 +0300 Subject: [PATCH 232/492] Rename nested test name --- .../io/spine/chatbot/server/google/chat/SpaceAggregateTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 74105854..169b3f2e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -85,7 +85,7 @@ void settingState() { @Nested @DisplayName("register a space when a bot is added to the space") - final class RegisterDirectly { + final class RegisterOnAddedBot { @BeforeEach void setUp() { From fa600d87be407692b61b13c95b080d16322d2d6a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Sun, 21 Jun 2020 17:37:15 +0300 Subject: [PATCH 233/492] Add missing EOF --- http-client.env.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-client.env.json b/http-client.env.json index 6dae7db5..68c063e6 100644 --- a/http-client.env.json +++ b/http-client.env.json @@ -3,4 +3,4 @@ "host": "api.travis-ci.com", "token": "" } -} \ No newline at end of file +} From 97d10e79e889ac23d10734a918b9a584d82226f1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 00:15:59 +0300 Subject: [PATCH 234/492] Add missing fields. --- .../src/main/proto/google/pubsub/v1/pubsub_push.proto | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto index 2205e71d..fcc7a5b2 100644 --- a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto +++ b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto @@ -10,6 +10,7 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "google/pubsub/v1/pubsub.proto"; +import "google/protobuf/timestamp.proto"; // Pubsub push message notification. message PubsubPushNotification { @@ -21,4 +22,10 @@ message PubsubPushNotification { // Format is `projects/{project}/subscriptions/{subscription}`. // string subscription = 2 [(required) = true, (pattern).regex = "projects/.+/subscriptions/.+"]; + + // Pubsub message ID. + string message_id = 3 [(required) = true]; + + // Message publishing time. + google.protobuf.Timestamp publish_time = 4 [(required) = true]; } From 89a1f3284e655e503f8d74baee522e8bc74eb893 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 10:09:43 +0300 Subject: [PATCH 235/492] Drop extra fields --- .../src/main/proto/google/pubsub/v1/pubsub_push.proto | 6 ------ 1 file changed, 6 deletions(-) diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto index fcc7a5b2..4d7466ae 100644 --- a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto +++ b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto @@ -22,10 +22,4 @@ message PubsubPushNotification { // Format is `projects/{project}/subscriptions/{subscription}`. // string subscription = 2 [(required) = true, (pattern).regex = "projects/.+/subscriptions/.+"]; - - // Pubsub message ID. - string message_id = 3 [(required) = true]; - - // Message publishing time. - google.protobuf.Timestamp publish_time = 4 [(required) = true]; } From a01f78b5670c3f2850415a6e65dbe51ecb6a95ae Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 11:29:13 +0300 Subject: [PATCH 236/492] Make sure pubsub notification is parsed correctly even if same field appears multiple time with different notations. --- .../java/io/spine/chatbot/BeanFactory.java | 29 ++++++- ...ubsubPushNotificationDeserializerTest.java | 79 +++++++++++++++++++ 2 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 6561972b..3dd87e1c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -23,6 +23,9 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.annotations.VisibleForTesting; +import com.google.pubsub.v1.PubsubMessage; import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.context.annotation.Bean; import io.micronaut.context.annotation.Factory; @@ -52,18 +55,36 @@ PubsubPushNotificationDeserializer pubsubDeserializer() { * @see * Jackson Deserialization */ - private static final class PubsubPushNotificationDeserializer + @VisibleForTesting + static final class PubsubPushNotificationDeserializer extends JsonDeserializer { /** * Deserializes {@link PubsubPushNotification} JSON string into a Protobuf message. + * + *

While Protobuf JSON parser is not able to handle same fields that are set using + * {@code lowerCamelCase} and {@code snake_case} notations, we manually drop duplicate + * fields. + * + * @see + * JsonFormat fails to parse JSON with both `lowerCamelCase` and `snake_case` + * fields */ @Override public PubsubPushNotification deserialize(JsonParser parser, DeserializationContext ctxt) { try { - var protoJson = parser.readValueAsTree() - .toString(); - var result = Json.fromJson(protoJson, PubsubPushNotification.class); + var jsonNode = ctxt.readTree(parser); + var messageNode = (ObjectNode) jsonNode.get("message"); + messageNode.remove("message_id"); + messageNode.remove("publish_time"); + var pubsubMessage = Json.fromJson(messageNode.toString(), PubsubMessage.class); + var subscription = jsonNode.get("subscription") + .asText(); + var result = PubsubPushNotification + .newBuilder() + .setMessage(pubsubMessage) + .setSubscription(subscription) + .vBuild(); return result; } catch (IOException e) { throw new RuntimeException("Unable to deserialize PubsubPushNotification json.", e); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java new file mode 100644 index 00000000..0e1265a9 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.truth.extensions.proto.ProtoTruth; +import com.google.protobuf.ByteString; +import com.google.protobuf.util.Timestamps; +import com.google.pubsub.v1.PubsubMessage; +import com.google.pubsub.v1.PubsubPushNotification; +import io.micronaut.jackson.ObjectMapperFactory; +import io.micronaut.test.annotation.MicronautTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import javax.inject.Inject; +import java.text.ParseException; + +@MicronautTest +@DisplayName("PubsubPushNotificationDeserializer should") +class PubsubPushNotificationDeserializerTest { + + @Inject + ObjectMapperFactory mapperFactory; + + @Test + @DisplayName("deserialize Pubsub message") + void deserializePubsubMessage() throws JsonProcessingException, ParseException { + + var pubsubMessage = PubsubMessage + .newBuilder() + .setMessageId("450292511223766") + .setPublishTime(Timestamps.parse("2020-06-21T20:48:25.908Z")) + .setData(ByteString.copyFromUtf8("{\"key\":\"value\"}")) + .buildPartial(); + var expectedResult = PubsubPushNotification + .newBuilder() + .setSubscription("projects/test-project/subscriptions/test-subscription") + .setMessage(pubsubMessage) + .vBuild(); + + var mapper = mapperFactory.objectMapper(null, null); + + var pushNotification = mapper.readValue(PUSH_NOTIFICATION_JSON, + PubsubPushNotification.class); + ProtoTruth.assertThat(pushNotification) + .isEqualTo(expectedResult); + } + + private static final String PUSH_NOTIFICATION_JSON = "" + + "{\n" + + " \"message\": {\n" + + " \"data\": \"eyJrZXkiOiJ2YWx1ZSJ9\",\n" + + " \"messageId\": \"450292511223766\",\n" + + " \"message_id\": \"450292511223766\",\n" + + " \"publishTime\": \"2020-06-21T20:48:25.908Z\",\n" + + " \"publish_time\": \"2020-06-21T20:48:25.908Z\"\n" + + " },\n" + + " \"subscription\": \"projects/test-project/subscriptions/test-subscription\"\n" + + "}"; +} From 35eeb01d536be90eba9ba792cbd8f34f7fb4f918 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 12:58:13 +0300 Subject: [PATCH 237/492] Configure log4j2 flogger backend --- google-chat-bot/build.gradle.kts | 5 +++++ .../main/java/io/spine/chatbot/Application.java | 17 +++++++++++++++++ google-chat-bot/src/main/resources/log4j2.xml | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/build.gradle.kts b/google-chat-bot/build.gradle.kts index 20df7b02..920eb774 100644 --- a/google-chat-bot/build.gradle.kts +++ b/google-chat-bot/build.gradle.kts @@ -49,6 +49,11 @@ dependencies { implementation(Deps.build.log4j2.core) runtimeOnly(Deps.build.log4j2.api) runtimeOnly(Deps.build.log4j2.slf4jBridge) + implementation(Deps.build.flogger) + implementation("com.google.flogger:flogger-log4j2-backend:${Deps.versions.flogger}") { + exclude("org.apache.logging.log4j:log4j-api") + exclude("org.apache.logging.log4j:log4j-core") + } implementation("io.spine.gcloud:spine-datastore:${Deps.versions.spineGcloud}") implementation(Deps.build.google.secretManager) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index ad075610..16dc7f1d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -21,9 +21,11 @@ package io.spine.chatbot; import com.google.common.annotations.VisibleForTesting; +import com.google.common.flogger.FluentLogger; import io.micronaut.runtime.Micronaut; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; +import io.spine.logging.Logging; import io.spine.server.Server; import java.io.IOException; @@ -45,6 +47,15 @@ **/ public final class Application { + static { + System.setProperty( + "flogger.backend_factory", + "com.google.common.flogger.backend.log4j2.Log4j2BackendFactory#getInstance" + ); + } + + private static final FluentLogger LOGGER = Logging.loggerFor(Application.class); + /** Name of the GRPC {@link Server}. **/ static final String SERVER_NAME = "ChatBotServer"; @@ -61,6 +72,8 @@ private Application() { * the {@link Micronaut}. */ public static void main(String[] args) { + LOGGER.atFine() + .log("Starting Spine ChatBot application."); initializeSpine(); Micronaut.run(Application.class, args); } @@ -69,6 +82,8 @@ public static void main(String[] args) { * Initializes Spine server environment and starts Spine {@link Server}. */ private static void initializeSpine() { + LOGGER.atConfig() + .log("Initializing server environment."); ChatBotServerEnvironment.initializeEnvironment(); var gitHubContext = GitHubContext .newBuilder() @@ -84,6 +99,8 @@ private static void initializeSpine() { */ @VisibleForTesting static void startSpineServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { + LOGGER.atConfig() + .log("Starting server."); Server server = Server .inProcess(SERVER_NAME) .add(gitHubContext.contextBuilder()) diff --git a/google-chat-bot/src/main/resources/log4j2.xml b/google-chat-bot/src/main/resources/log4j2.xml index 4bcbb06a..f1783116 100644 --- a/google-chat-bot/src/main/resources/log4j2.xml +++ b/google-chat-bot/src/main/resources/log4j2.xml @@ -21,7 +21,7 @@ - + From f700a9d0d40124e3f5f1612bfd0cc9dd27aed61b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 13:14:44 +0300 Subject: [PATCH 238/492] Google Chat events are delivered as PubSub messages but without base64 encoding of the `data` --- .../io/spine/chatbot/IncomingEventsController.java | 13 ++----------- .../spine/chatbot/IncomingEventsControllerTest.java | 9 +-------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index e8d82a5c..d60f0841 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -20,7 +20,6 @@ package io.spine.chatbot; -import com.google.protobuf.ByteString; import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; @@ -32,9 +31,6 @@ import io.spine.logging.Logging; import io.spine.server.integration.ThirdPartyContext; -import java.nio.charset.StandardCharsets; -import java.util.Base64; - import static io.micronaut.http.MediaType.APPLICATION_JSON; import static io.spine.util.Exceptions.newIllegalStateException; @@ -54,7 +50,8 @@ final class IncomingEventsController implements Logging { @Post(value = "/incoming/event", consumes = APPLICATION_JSON) String on(@Body PubsubPushNotification pushNotification) { var message = pushNotification.getMessage(); - var chatEventJson = decodeBase64Json(message.getData()); + var chatEventJson = message.getData() + .toStringUtf8(); _debug().log("Received a new chat event: %s", chatEventJson); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); var actor = eventActor(chatEvent.getUser()); @@ -72,10 +69,4 @@ private static UserId eventActor(User user) { .setValue(user.getName()) .vBuild(); } - - private static String decodeBase64Json(ByteString encoded) { - var decodedBytes = Base64.getDecoder() - .decode(encoded.toByteArray()); - return new String(decodedBytes, StandardCharsets.UTF_8); - } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index fcf199ad..4247da1a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -37,8 +37,6 @@ import org.junit.jupiter.api.Test; import javax.inject.Inject; -import java.nio.charset.StandardCharsets; -import java.util.Base64; import static io.micronaut.http.HttpRequest.POST; import static io.spine.chatbot.Application.startSpineServer; @@ -73,7 +71,7 @@ void receiveAndDecode() { var pubsubMessage = PubsubMessage .newBuilder() .setMessageId("129y418y4houfhiuehwr") - .setData(base64Encode(CHAT_MESSAGE_EVENT)) + .setData(ByteString.copyFromUtf8(CHAT_MESSAGE_EVENT)) .build(); var pushNotification = PubsubPushNotification .newBuilder() @@ -87,11 +85,6 @@ void receiveAndDecode() { assertEquals("OK", actual); } - private static ByteString base64Encode(String value) { - var encoder = Base64.getEncoder(); - return ByteString.copyFrom(encoder.encode(value.getBytes(StandardCharsets.UTF_8))); - } - private static final String CHAT_MESSAGE_EVENT = "" + "{\n" + " \"type\":\"MESSAGE\",\n" + From 7a40d68ff09a1e9d838e5452d030b5d7887b3ef3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 14:39:37 +0300 Subject: [PATCH 239/492] BotAddedToSpace is not external event --- .../server/google/chat/SpaceAggregate.java | 15 +++++++++------ .../server/google/chat/SpaceAggregateTest.java | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 60d3397c..267c0648 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -26,7 +26,6 @@ import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.google.chat.incoming.SpaceType; import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; -import io.spine.core.External; import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; import io.spine.server.aggregate.Apply; @@ -44,14 +43,17 @@ final class SpaceAggregate extends Aggregate impl * Registers a new space when the ChatBot is added to the space. */ @React - SpaceRegistered on(@External BotAddedToSpace e) { + SpaceRegistered on(BotAddedToSpace e) { var space = e.getEvent() .getSpace(); + var displayName = space.getDisplayName(); + var spaceId = e.getSpaceId(); + _info().log("Registering space `%s` (`%s`).", displayName, spaceId.getValue()); return SpaceRegistered .newBuilder() - .setDisplayName(space.getDisplayName()) + .setDisplayName(displayName) .setThreaded(isThreaded(space)) - .setId(e.getSpaceId()) + .setId(spaceId) .vBuild(); } @@ -60,10 +62,11 @@ SpaceRegistered on(@External BotAddedToSpace e) { */ @Assign SpaceRegistered handle(RegisterSpace c) { - _info().log("Registering space `%s`.", idAsString()); + var spaceId = c.getId(); + _info().log("Registering space `%s`.", spaceId.getValue()); var result = SpaceRegistered .newBuilder() - .setId(c.getId()) + .setId(spaceId) .setSingleUserBotDm(c.getSingleUserBotDm()) .setThreaded(c.getThreaded()) .setDisplayName(c.getDisplayName()) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 169b3f2e..b71baba9 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -102,7 +102,7 @@ void setUp() { .setSpaceId(spaceId) .setEvent(chatEvent) .vBuild(); - context().receivesExternalEvent(botAddedToSpace); + context().receivesEvent(botAddedToSpace); } @Test From 35007fa647aa07baf4c62b0cc703868484d51b4b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 14:40:21 +0300 Subject: [PATCH 240/492] Add more logs --- .../server/github/RepoBuildProcess.java | 22 ++++++++++++++----- .../server/github/SpineOrgInitProcess.java | 6 ++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 401fe660..daa66148 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -37,6 +37,7 @@ import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildStable; import io.spine.chatbot.github.repository.build.rejection.NoBuildsFound; +import io.spine.logging.Logging; import io.spine.net.Urls; import io.spine.server.command.Assign; import io.spine.server.procman.ProcessManager; @@ -67,7 +68,8 @@ * Or, if the repository builds could not be retrieved, throws {@link NoBuildsFound} rejection. */ final class RepoBuildProcess - extends ProcessManager { + extends ProcessManager + implements Logging { @LazyInit private @MonotonicNonNull TravisClient travisClient; @@ -81,12 +83,15 @@ final class RepoBuildProcess @Assign EitherOf3 handle(CheckRepositoryBuild c) throws NoBuildsFound { - var builds = travisClient.execute(BuildsQuery.forRepo(id().getValue())) + var repositoryId = c.getId(); + _info().log("Checking build status for repository `%s`.", repositoryId.getValue()); + var builds = travisClient.execute(BuildsQuery.forRepo(repositoryId.getValue())) .getBuildsList(); if (builds.isEmpty()) { + _warn().log("No builds found for the repository `%s`.", repositoryId.getValue()); throw NoBuildsFound .newBuilder() - .setId(c.getId()) + .setId(repositoryId) .build(); } var build = builds.get(0); @@ -98,15 +103,18 @@ EitherOf3 handle(CheckRepositoryBuild .setPreviousValue(state().getBuildState()) .setNewValue(buildState) .vBuild(); - var result = determineOutcome(c.getId(), stateChange); + var result = determineOutcome(repositoryId, stateChange); return result; } - private static EitherOf3 + private EitherOf3 determineOutcome(RepositoryId id, BuildStateChange stateChange) { - var stateStatusChange = stateStatusChangeOf(stateChange.getNewValue()); + var newBuildState = stateChange.getNewValue(); + var stateStatusChange = stateStatusChangeOf(newBuildState); switch (stateStatusChange) { case FAILED: + _info().log("Build for repository `%s` failed with status `%s`.", + id.getValue(), newBuildState.getState()); var buildFailed = BuildFailed .newBuilder() .setId(id) @@ -114,6 +122,7 @@ EitherOf3 handle(CheckRepositoryBuild .vBuild(); return EitherOf3.withA(buildFailed); case RECOVERED: + _info().log("Build for repository `%s` is recovered.", id.getValue()); var buildRecovered = BuildRecovered .newBuilder() .setId(id) @@ -121,6 +130,7 @@ EitherOf3 handle(CheckRepositoryBuild .vBuild(); return EitherOf3.withB(buildRecovered); case STABLE: + _info().log("Build for repository `%s` is stable.", id.getValue()); var buildStable = BuildStable .newBuilder() .setId(id) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 280c1ac9..16cb5059 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -76,9 +76,12 @@ final class SpineOrgInitProcess @Command Iterable on(@External SpaceRegistered e) { if (state().getInitialized()) { + _info().log("Spine organization is already initialized. Skipping the process."); return ImmutableSet.of(); } var spaceId = e.getId(); + _info().log("Starting Spine organization initialization process in space `%s`.", + spaceId.getValue()); var commands = ImmutableSet.builder(); commands.add(registerOrgCommand(SPINE_ORGANIZATION, spaceId.getValue())); travisClient.execute(ReposQuery.forOwner(SPINE_ORG)) @@ -92,8 +95,9 @@ Iterable on(@External SpaceRegistered e) { return commands.build(); } - private static RegisterRepository registerRepoCommand(Repository repo, OrganizationId orgId) { + private RegisterRepository registerRepoCommand(Repository repo, OrganizationId orgId) { var slug = repo.getSlug(); + _info().log("Registering `%s` repository.", slug); return RegisterRepository .newBuilder() .setOrganization(orgId) From 87ceb8a88d3227cdb012c53be5c091da58058a38 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 14:59:17 +0300 Subject: [PATCH 241/492] drop log4j2 configuration logs --- google-chat-bot/src/main/resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/resources/log4j2.xml b/google-chat-bot/src/main/resources/log4j2.xml index f1783116..c15315ac 100644 --- a/google-chat-bot/src/main/resources/log4j2.xml +++ b/google-chat-bot/src/main/resources/log4j2.xml @@ -18,7 +18,7 @@ ~ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + From cc829f4bcf54ce0976a0d43fccbdaf682afd3299 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 15:48:57 +0300 Subject: [PATCH 242/492] Include google chat space and org ID into repos build check process --- .../spine/chatbot/RepositoriesController.java | 19 +++++++--- .../chatbot/api/google/chat/GoogleChat.java | 10 ++++- .../chatbot/client/ChatBotServerClient.java | 24 ++++++++++++ .../server/github/RepoBuildProcess.java | 6 ++- .../chatbot/github/repository_build.proto | 4 +- .../github/repository_build_commands.proto | 6 +++ .../server/github/RepoBuildProcessTest.java | 37 ++++++++++++++----- 7 files changed, 85 insertions(+), 21 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index fc08c266..515cf13a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -24,6 +24,7 @@ import io.micronaut.http.annotation.Post; import io.spine.chatbot.client.ChatBotServerClient; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.logging.Logging; @@ -43,15 +44,20 @@ final class RepositoriesController implements Logging { String checkBuildStatuses() { _debug().log("Checking repositories build statues."); var botClient = ChatBotServerClient.inProcessClient(SERVER_NAME); - botClient.listRepositories() - .forEach(repository -> checkBuildStatus(botClient, repository)); + var organizations = botClient.listOrganizations(); + for (var organization : organizations) { + var repos = botClient.listOrgRepos(organization.getId()); + repos.forEach(repo -> checkBuildStatus(botClient, repo, organization)); + } return "success"; } - private void checkBuildStatus(ChatBotServerClient botClient, RepositoryId repository) { + private void checkBuildStatus(ChatBotServerClient botClient, + RepositoryId repository, + Organization organization) { _info().log("Sending `CheckRepositoryBuild` command for repository `%s`", repository.getValue()); - var checkRepositoryBuild = checkRepoBuildCommand(repository); + var checkRepositoryBuild = checkRepoBuildCommand(repository, organization); var subscriptions = botClient .asGuest() .command(checkRepositoryBuild) @@ -66,10 +72,13 @@ private static void throwProcessingError(Throwable throwable) { ); } - private static CheckRepositoryBuild checkRepoBuildCommand(RepositoryId id) { + private static CheckRepositoryBuild + checkRepoBuildCommand(RepositoryId id, Organization organization) { return CheckRepositoryBuild .newBuilder() .setId(id) + .setOrganization(organization.getId()) + .setGoogleChatSpace(organization.getGoogleChatSpace()) .vBuild(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index a31fcf10..ee300d2d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -64,8 +64,9 @@ public static GoogleChatClient instance() { @Override public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread) { var repoSlug = buildState.getRepositorySlug(); - _debug().log("Sending build state update message for repository `%s`.", repoSlug); + _debug().log("Building state update message for repository `%s`.", repoSlug); var message = buildStateMessage(buildState, thread); + _debug().log("Sending state update message for repository `%s`.", repoSlug); var result = sendMessage(buildState.getGoogleChatSpace(), message); _debug().log( "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", @@ -84,6 +85,7 @@ private Message sendMessage(String space, Message message) { .create(space, message) .execute(); } catch (IOException e) { + _error().log("Unable to send message to space `%s`.", space, e); throw new RuntimeException("Unable to send message to space " + space, e); } } @@ -101,7 +103,11 @@ private static HangoutsChat hangoutsChat() { .build(); return chat; } catch (IOException | GeneralSecurityException e) { - throw new RuntimeException("Unable to create Hangouts Chat client", e); + String message = "Unable to create Hangouts Chat client."; + Logging.loggerFor(GoogleChat.class) + .atSevere() + .log(message, e); + throw new RuntimeException(message, e); } } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java index 99a5e0e7..3dc74e81 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java @@ -24,6 +24,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.base.CommandMessage; import io.spine.base.EventMessage; +import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; @@ -35,6 +36,7 @@ import java.util.Collection; import java.util.concurrent.CountDownLatch; +import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.ImmutableList.toImmutableList; /** @@ -79,6 +81,28 @@ public boolean cancelSubscription(Subscription subscription) { .cancel(subscription); } + /** + * Retrieves all registered organizations. + */ + public ImmutableList listOrganizations() { + return client.asGuest() + .select(Organization.class) + .run(); + } + + /** + * Returns list of all registered repositories for the {@code organization}. + */ + public ImmutableList listOrgRepos(OrganizationId organization) { + var orgRepos = client.asGuest() + .select(OrganizationRepositories.class) + .byId(organization) + .run(); + checkState(orgRepos.size() == 1); + return ImmutableList.copyOf(orgRepos.get(0) + .getRepositoriesList()); + } + /** * Returns IDs for all registered repositories. */ diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index daa66148..eab07026 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -95,7 +95,7 @@ EitherOf3 handle(CheckRepositoryBuild .build(); } var build = builds.get(0); - var buildState = buildStateFrom(build); + var buildState = buildStateFrom(build, c.getGoogleChatSpace()); builder().setLastStatusCheck(Time.currentTime()) .setBuildState(buildState); var stateChange = BuildStateChange @@ -165,11 +165,13 @@ private static BuildStateStatusChange stateStatusChangeOf(BuildState buildState) } @VisibleForTesting - static BuildState buildStateFrom(Build build) { + static BuildState buildStateFrom(Build build, String space) { var slug = build.getRepository() .getSlug(); return BuildState .newBuilder() + .setNumber(build.getNumber()) + .setGoogleChatSpace(space) .setState(BuildStates.buildStateFrom(build.getState())) .setPreviousState(BuildStates.buildStateFrom(build.getPreviousState())) .setBranch(build.getBranch() diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 3fb965ac..227aaa9d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -144,11 +144,11 @@ message BuildState { string authored_by = 5; } - // The repository slug the builds is associated with. + // The repository slug the build is associated with. string repository_slug = 8; // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 9; + string google_chat_space = 9 [(required) = true, (pattern).regex = "spaces/.+"]; } // Definition of a change in a `build_state` field. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 59790b94..85139970 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -38,4 +38,10 @@ message CheckRepositoryBuild { // ID of the repository to perform a check for. RepositoryId id = 1 [(required) = true]; + + // ID of the organization the repository belongs to. + OrganizationId organization = 2 [(required) = true]; + + // Name of the Google Chat space associated with the organization in form `spaces/`. + string google_chat_space = 3 [(required) = true, (pattern).regex = "spaces/.+"]; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index e91a644f..428f209d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -24,6 +24,7 @@ import io.spine.chatbot.api.travis.BuildsResponse; import io.spine.chatbot.api.travis.Commit; import io.spine.chatbot.api.travis.Repository; +import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; @@ -38,13 +39,16 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; import static io.spine.chatbot.server.github.RepoBuildProcess.buildStateFrom; @DisplayName("RepoBuildProcess should") final class RepoBuildProcessTest extends GitHubContextAwareTest { + private static final OrganizationId orgId = organizationIdOf("SpineEventEngine"); private static final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/web"); + private static final String chatSpace = "spaces/1245wrq"; @Test @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") @@ -53,6 +57,8 @@ void throwNoBuildsFoundRejection() { var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) + .setOrganization(orgId) + .setGoogleChatSpace(chatSpace) .vBuild(); context().receivesCommand(checkRepoBuild); @@ -69,7 +75,7 @@ void throwNoBuildsFoundRejection() { final class FailedBuild { private final Build build = failedBuild(); - private final BuildState buildState = buildStateFrom(build); + private final BuildState buildState = buildStateFrom(build, chatSpace); @BeforeEach void setUp() { @@ -77,6 +83,8 @@ void setUp() { var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) + .setGoogleChatSpace(chatSpace) + .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoBuild); } @@ -115,10 +123,10 @@ void settingState() { final class RecoveredBuild { private final Build previousBuild = failedBuild(); - private final BuildState previousBuildState = buildStateFrom(previousBuild); + private final BuildState previousBuildState = buildStateFrom(previousBuild, chatSpace); private final Build newBuild = passingBuild(); - private final BuildState newBuildState = buildStateFrom(newBuild); + private final BuildState newBuildState = buildStateFrom(newBuild, chatSpace); @BeforeEach void setUp() { @@ -126,12 +134,16 @@ void setUp() { var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) + .setGoogleChatSpace(chatSpace) + .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) + .setGoogleChatSpace(chatSpace) + .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoRecovery); } @@ -171,10 +183,10 @@ void settingState() { final class StableBuild { private final Build previousBuild = passingBuild(); - private final BuildState previousBuildState = buildStateFrom(previousBuild); + private final BuildState previousBuildState = buildStateFrom(previousBuild, chatSpace); private final Build newBuild = nextPassingBuild(); - private final BuildState newBuildState = buildStateFrom(newBuild); + private final BuildState newBuildState = buildStateFrom(newBuild, chatSpace); @BeforeEach void setUp() { @@ -182,12 +194,16 @@ void setUp() { var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) + .setGoogleChatSpace(chatSpace) + .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) + .setGoogleChatSpace(chatSpace) + .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoRecovery); } @@ -317,10 +333,11 @@ private static Commit fatefulCommit() { } private static Repository webRepository() { - return Repository.newBuilder() - .setId(1112) - .setName("web") - .setSlug(repositoryId.getValue()) - .buildPartial(); + return Repository + .newBuilder() + .setId(1112) + .setName("web") + .setSlug(repositoryId.getValue()) + .buildPartial(); } } From 7b444e527f540667cac49eb6b68b4dcf240b4f23 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 16:04:33 +0300 Subject: [PATCH 243/492] Expose current repo build state as a column --- .../io/spine/chatbot/server/github/RepoBuildProcess.java | 1 + .../main/proto/spine/chatbot/github/repository_build.proto | 5 ++++- .../io/spine/chatbot/server/github/RepoBuildProcessTest.java | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index eab07026..17f3cdfa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -97,6 +97,7 @@ EitherOf3 handle(CheckRepositoryBuild var build = builds.get(0); var buildState = buildStateFrom(build, c.getGoogleChatSpace()); builder().setLastStatusCheck(Time.currentTime()) + .setRepositoryBuildState(buildState.getState()) .setBuildState(buildState); var stateChange = BuildStateChange .newBuilder() diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 227aaa9d..b0df9197 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -49,6 +49,9 @@ message RepositoryBuild { // Current state of the build. BuildState build_state = 3; + + // Current repository build state. + BuildState.State repository_build_state = 4 [(column) = true]; } // The state change status of the build. @@ -148,7 +151,7 @@ message BuildState { string repository_slug = 8; // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 9 [(required) = true, (pattern).regex = "spaces/.+"]; + string google_chat_space = 9 [(pattern).regex = "spaces/.+"]; } // Definition of a change in a `build_state` field. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 428f209d..29459609 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -111,6 +111,7 @@ void settingState() { .newBuilder() .setId(repositoryId) .setBuildState(buildState) + .setRepositoryBuildState(buildState.getState()) .vBuild(); context().assertState(repositoryId, RepositoryBuild.class) .isEqualTo(expectedState); @@ -171,6 +172,7 @@ void settingState() { .newBuilder() .setId(repositoryId) .setBuildState(newBuildState) + .setRepositoryBuildState(newBuildState.getState()) .vBuild(); context().assertState(repositoryId, RepositoryBuild.class) .isEqualTo(expectedState); @@ -231,6 +233,7 @@ void settingState() { .newBuilder() .setId(repositoryId) .setBuildState(newBuildState) + .setRepositoryBuildState(newBuildState.getState()) .vBuild(); context().assertState(repositoryId, RepositoryBuild.class) .isEqualTo(expectedState); From 530baf2b3a04c2ded1f30820dda48c93464b9bb7 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 16:29:42 +0300 Subject: [PATCH 244/492] Switch to `branch` API for the latest build state. The `repos` API actually returns not only the build for the branch itself, but also builds for respective related PR that are gonna be merged into the branch --- .../spine/chatbot/api/travis/BuildsQuery.java | 6 ++--- .../server/github/RepoBuildProcess.java | 8 +++---- .../proto/spine/chatbot/travis/travis.proto | 22 ++++++++++++++----- .../api/travis/InMemoryTravisClient.java | 8 +++---- .../server/github/RepoBuildProcessTest.java | 21 +++++++++--------- travis-ci.http | 7 ++++++ 6 files changed, 46 insertions(+), 26 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index 50e4521f..af01b672 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -25,10 +25,10 @@ * * @see Find build */ -public final class BuildsQuery extends Query { +public final class BuildsQuery extends Query { private BuildsQuery(String request) { - super(request, BuildsResponse.class); + super(request, RepoBranchBuildResponse.class); } /** @@ -40,7 +40,7 @@ public static BuildsQuery forRepo(String repoSlug) { var encodedSlug = encode(repoSlug); var request = "/repo/" + encodedSlug - + "/builds?limit=1&branch.name=master&include=build.commit"; + + "/branch/master?&include=build.commit"; return new BuildsQuery(request); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 17f3cdfa..9837767f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -49,6 +49,7 @@ import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; import static io.spine.net.Urls.travisBuildUrlFor; +import static io.spine.protobuf.Messages.isDefault; import static io.spine.util.Exceptions.newIllegalStateException; /** @@ -85,16 +86,15 @@ EitherOf3 handle(CheckRepositoryBuild throws NoBuildsFound { var repositoryId = c.getId(); _info().log("Checking build status for repository `%s`.", repositoryId.getValue()); - var builds = travisClient.execute(BuildsQuery.forRepo(repositoryId.getValue())) - .getBuildsList(); - if (builds.isEmpty()) { + var branchBuild = travisClient.execute(BuildsQuery.forRepo(repositoryId.getValue())); + if (isDefault(branchBuild.getLastBuild())) { _warn().log("No builds found for the repository `%s`.", repositoryId.getValue()); throw NoBuildsFound .newBuilder() .setId(repositoryId) .build(); } - var build = builds.get(0); + var build = branchBuild.getLastBuild(); var buildState = buildStateFrom(build, c.getGoogleChatSpace()); builder().setLastStatusCheck(Time.currentTime()) .setRepositoryBuildState(buildState.getState()) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index d2f926ab..19b4c7a9 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -135,16 +135,28 @@ message Build { Owner created_by = 11; } -// A Travis `builds` API endpoint response. -message BuildsResponse { +// A Travis `branch` API endpoint response. +message RepoBranchBuildResponse { option (is).java_type = "TravisResponse"; - // Builds fetched by the API call. - repeated Build builds = 1; + // Name of the git branch. + string name = 1; + + // The repository. + Repository repository = 2; + + // Whether or not this is the repository's default branch. + bool default_branch = 3; + + // Whether or not the branch still exists on GitHub. + bool exists_on_github = 4; + + // Last build on the branch. + Build last_build = 5; } -// A travis `repos` API endpoint response. +// A Travis `repos` API endpoint response. message RepositoriesResponse { option (is).java_type = "TravisResponse"; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java index 303c9d21..5461b142 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java @@ -63,12 +63,12 @@ public T execute(Query query) { } /** - * Sets up a stub {@code builds} response for a specified {@code repoSlug}. + * Sets up a stub {@code branchBuild} response for a specified {@code repoSlug}. */ - public void setBuildsFor(String repoSlug, BuildsResponse builds) { + public void setBuildsFor(String repoSlug, RepoBranchBuildResponse branchBuild) { checkNotNull(repoSlug); - checkNotNull(builds); - responses.put(BuildsQuery.forRepo(repoSlug), builds); + checkNotNull(branchBuild); + responses.put(BuildsQuery.forRepo(repoSlug), branchBuild); } /** diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 29459609..07783dca 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -21,8 +21,8 @@ package io.spine.chatbot.server.github; import io.spine.chatbot.api.travis.Build; -import io.spine.chatbot.api.travis.BuildsResponse; import io.spine.chatbot.api.travis.Commit; +import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; @@ -53,7 +53,8 @@ final class RepoBuildProcessTest extends GitHubContextAwareTest { @Test @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") void throwNoBuildsFoundRejection() { - travisClient().setBuildsFor(repositoryId.getValue(), BuildsResponse.getDefaultInstance()); + travisClient().setBuildsFor(repositoryId.getValue(), + RepoBranchBuildResponse.getDefaultInstance()); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -79,7 +80,7 @@ final class FailedBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(build)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(build)); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -131,7 +132,7 @@ final class RecoveredBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(previousBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -139,7 +140,7 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(newBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -192,7 +193,7 @@ final class StableBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(previousBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -200,7 +201,7 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), singleBuild(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(newBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -240,10 +241,10 @@ void settingState() { } } - private static BuildsResponse singleBuild(Build build) { - return BuildsResponse + private static RepoBranchBuildResponse branchBuildOf(Build build) { + return RepoBranchBuildResponse .newBuilder() - .addBuilds(build) + .setLastBuild(build) .buildPartial(); } diff --git a/travis-ci.http b/travis-ci.http index fa4f5d3f..a1bb46de 100644 --- a/travis-ci.http +++ b/travis-ci.http @@ -11,3 +11,10 @@ GET https://{{host}}/owner/SpineEventEngine/repos Accept: application/json Authorization: token {{token}} Travis-API-Version: 3 + +### List Travis CI repository branch builds + +GET https://{{host}}/repo/SpineEventEngine%2Fcore-java/branch/master?limit=3&include=build.commit +Accept: application/json +Authorization: token {{token}} +Travis-API-Version: 3 From 18472cb7f91e79932aaaf63c1e6e4f44783fa606 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 16:42:54 +0300 Subject: [PATCH 245/492] Use our own state do determine whether a build is recovered or stable. Trigger builds as recovered only if we previously had them as failed in the process. --- .../chatbot/server/github/RepoBuildProcess.java | 13 ++++++++----- .../server/github/RepoBuildProcessTest.java | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 9837767f..f9556b99 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -45,6 +45,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import static io.spine.chatbot.github.repository.build.BuildState.State.PASSED; +import static io.spine.chatbot.github.repository.build.BuildState.State.S_UNKNOWN; import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.FAILED; import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; @@ -111,7 +112,8 @@ EitherOf3 handle(CheckRepositoryBuild private EitherOf3 determineOutcome(RepositoryId id, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); - var stateStatusChange = stateStatusChangeOf(newBuildState); + var previousBuildState = stateChange.getPreviousValue(); + var stateStatusChange = stateStatusChangeOf(newBuildState, previousBuildState); switch (stateStatusChange) { case FAILED: _info().log("Build for repository `%s` failed with status `%s`.", @@ -147,16 +149,17 @@ EitherOf3 handle(CheckRepositoryBuild } } - private static BuildStateStatusChange stateStatusChangeOf(BuildState buildState) { - var currentState = buildState.getState(); - var previousState = buildState.getPreviousState(); + private static BuildStateStatusChange stateStatusChangeOf(BuildState newBuildState, + BuildState previousBuildState) { + var currentState = newBuildState.getState(); + var previousState = previousBuildState.getState(); if (BuildStates.isFailed(currentState)) { return FAILED; } if (currentState == PASSED && BuildStates.isFailed(previousState)) { return RECOVERED; } - if (currentState == PASSED && previousState == PASSED) { + if (currentState == PASSED && (previousState == PASSED || previousState == S_UNKNOWN)) { return STABLE; } throw newIllegalStateException( diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 07783dca..83ff3f67 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -185,6 +185,8 @@ void settingState() { @DisplayName("handle stable builds") final class StableBuild { + private final Build initialFailedBuild = failedBuild(); + private final Build previousBuild = passingBuild(); private final BuildState previousBuildState = buildStateFrom(previousBuild, chatSpace); @@ -193,7 +195,7 @@ final class StableBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(initialFailedBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -201,7 +203,7 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(previousBuild)); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -209,6 +211,14 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoRecovery); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(newBuild)); + var checkRepoStable = CheckRepositoryBuild + .newBuilder() + .setId(repositoryId) + .setGoogleChatSpace(chatSpace) + .setOrganization(orgId) + .vBuild(); + context().receivesCommand(checkRepoStable); } @Test From 0fd30f79549fd74670df9c6fcc142fc073f24a87 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 17:10:13 +0300 Subject: [PATCH 246/492] use info from the RepoBranchBuildResponse and not only from the build itself. E.g. grab Repository and branch name from the response --- .../spine/chatbot/api/travis/BuildsQuery.java | 8 ++--- .../server/github/RepoBuildProcess.java | 16 +++++----- .../server/github/RepoBuildProcessTest.java | 30 ++++++++++++------- travis-ci.http | 2 +- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index af01b672..b3a1cb31 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -21,9 +21,9 @@ package io.spine.chatbot.api.travis; /** - * Travis CI builds API query. + * Travis CI branch builds API query. * - * @see Find build + * @see Find branch build. */ public final class BuildsQuery extends Query { @@ -32,7 +32,7 @@ private BuildsQuery(String request) { } /** - * Creates a repository builds query for a repository with the specified {@code slug}. + * Creates a repository branch builds query for a repository with the specified {@code slug}. * *

Requests only a single build from the {@code master} branch */ @@ -40,7 +40,7 @@ public static BuildsQuery forRepo(String repoSlug) { var encodedSlug = encode(repoSlug); var request = "/repo/" + encodedSlug - + "/branch/master?&include=build.commit"; + + "/branch/master?&include=build.commit,build.created_by"; return new BuildsQuery(request); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index f9556b99..3e1c615c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -23,9 +23,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; -import io.spine.chatbot.api.travis.Build; import io.spine.chatbot.api.travis.BuildsQuery; import io.spine.chatbot.api.travis.Commit; +import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; @@ -95,8 +95,7 @@ EitherOf3 handle(CheckRepositoryBuild .setId(repositoryId) .build(); } - var build = branchBuild.getLastBuild(); - var buildState = buildStateFrom(build, c.getGoogleChatSpace()); + var buildState = buildStateFrom(branchBuild, c.getGoogleChatSpace()); builder().setLastStatusCheck(Time.currentTime()) .setRepositoryBuildState(buildState.getState()) .setBuildState(buildState); @@ -169,17 +168,18 @@ private static BuildStateStatusChange stateStatusChangeOf(BuildState newBuildSta } @VisibleForTesting - static BuildState buildStateFrom(Build build, String space) { - var slug = build.getRepository() - .getSlug(); + static BuildState buildStateFrom(RepoBranchBuildResponse branchBuild, String space) { + var branchBuildName = branchBuild.getName(); + var slug = branchBuild.getRepository() + .getSlug(); + var build = branchBuild.getLastBuild(); return BuildState .newBuilder() .setNumber(build.getNumber()) .setGoogleChatSpace(space) .setState(BuildStates.buildStateFrom(build.getState())) .setPreviousState(BuildStates.buildStateFrom(build.getPreviousState())) - .setBranch(build.getBranch() - .getName()) + .setBranch(branchBuildName) .setLastCommit(from(build.getCommit())) .setCreatedBy(build.getCreatedBy() .getLogin()) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 83ff3f67..4b35084b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -76,11 +76,12 @@ void throwNoBuildsFoundRejection() { final class FailedBuild { private final Build build = failedBuild(); - private final BuildState buildState = buildStateFrom(build, chatSpace); + private final RepoBranchBuildResponse branchBuild = branchBuildOf(build); + private final BuildState buildState = buildStateFrom(branchBuild, chatSpace); @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(build)); + travisClient().setBuildsFor(repositoryId.getValue(), branchBuild); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -125,14 +126,17 @@ void settingState() { final class RecoveredBuild { private final Build previousBuild = failedBuild(); - private final BuildState previousBuildState = buildStateFrom(previousBuild, chatSpace); + private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); + private final BuildState previousBuildState = buildStateFrom(previousBranchBuild, + chatSpace); private final Build newBuild = passingBuild(); - private final BuildState newBuildState = buildStateFrom(newBuild, chatSpace); + private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); + private final BuildState newBuildState = buildStateFrom(newBranchBuild, chatSpace); @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), previousBranchBuild); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -140,7 +144,7 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), newBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -188,10 +192,13 @@ final class StableBuild { private final Build initialFailedBuild = failedBuild(); private final Build previousBuild = passingBuild(); - private final BuildState previousBuildState = buildStateFrom(previousBuild, chatSpace); + private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); + private final BuildState previousBuildState = buildStateFrom(previousBranchBuild, + chatSpace); private final Build newBuild = nextPassingBuild(); - private final BuildState newBuildState = buildStateFrom(newBuild, chatSpace); + private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); + private final BuildState newBuildState = buildStateFrom(newBranchBuild, chatSpace); @BeforeEach void setUp() { @@ -203,7 +210,7 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(previousBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), previousBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -211,7 +218,7 @@ void setUp() { .setOrganization(orgId) .vBuild(); context().receivesCommand(checkRepoRecovery); - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(newBuild)); + travisClient().setBuildsFor(repositoryId.getValue(), newBranchBuild); var checkRepoStable = CheckRepositoryBuild .newBuilder() .setId(repositoryId) @@ -255,6 +262,9 @@ private static RepoBranchBuildResponse branchBuildOf(Build build) { return RepoBranchBuildResponse .newBuilder() .setLastBuild(build) + .setName("master") + .setRepository(Repository.newBuilder() + .setSlug(repositoryId.getValue())) .buildPartial(); } diff --git a/travis-ci.http b/travis-ci.http index a1bb46de..7b02c0a3 100644 --- a/travis-ci.http +++ b/travis-ci.http @@ -14,7 +14,7 @@ Travis-API-Version: 3 ### List Travis CI repository branch builds -GET https://{{host}}/repo/SpineEventEngine%2Fcore-java/branch/master?limit=3&include=build.commit +GET https://{{host}}/repo/SpineEventEngine%2Fcore-java/branch/master?include=build.commit,build.created_by Accept: application/json Authorization: token {{token}} Travis-API-Version: 3 From a32f86a5b7f5882a82409760b8a52a64e7d03622 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 17:18:01 +0300 Subject: [PATCH 247/492] Fix capitalization --- .../io/spine/chatbot/api/google/chat/BuildStateUpdates.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index e8606110..a8945cf0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -114,6 +114,7 @@ private static WidgetMarkup buildStateWidget(BuildState buildState) { private static String capitalizeState(BuildState.State state) { var name = state.name(); - return name.charAt(0) + name.toLowerCase(); + return name.charAt(0) + name.substring(1) + .toLowerCase(); } } From 99cf91620c5597301ea5f6b1773df9f33ba21f93 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 20:59:13 +0300 Subject: [PATCH 248/492] Add missing EOLs --- .idea/codeStyleSettings.xml | 2 +- .idea/codeStyles/Project.xml | 2 +- .idea/codeStyles/codeStyleConfig.xml | 2 +- .idea/misc.xml | 2 +- .idea/vcs.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index 123c5876..7cd03408 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -49,4 +49,4 @@ - \ No newline at end of file + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f..5ace414d 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -3,4 +3,4 @@ - \ No newline at end of file + From 7a1e893cf8859dc8ad5e394149acf9d46b95f47a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 21:00:54 +0300 Subject: [PATCH 249/492] Shorten `initializeEnvironment` to `init`. --- google-chat-bot/src/main/java/io/spine/chatbot/Application.java | 2 +- .../main/java/io/spine/chatbot/ChatBotServerEnvironment.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 16dc7f1d..85950be6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -84,7 +84,7 @@ public static void main(String[] args) { private static void initializeSpine() { LOGGER.atConfig() .log("Initializing server environment."); - ChatBotServerEnvironment.initializeEnvironment(); + ChatBotServerEnvironment.init(); var gitHubContext = GitHubContext .newBuilder() .build(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index c6875926..16bf11b2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -53,7 +53,7 @@ private ChatBotServerEnvironment() { /** * Initializes {@link ServerEnvironment} for ChatBot. */ - static void initializeEnvironment() { + static void init() { var se = ServerEnvironment.instance(); var storageFactory = dsStorageFactory(); se.use(InMemoryTransportFactory.newInstance(), Production.class); From fb91c312fea8e276315e4dcfebca725bd0d28597 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 21:03:37 +0300 Subject: [PATCH 250/492] rename `instance` to `newInstance` --- .../java/io/spine/chatbot/api/google/chat/GoogleChat.java | 2 +- .../src/main/java/io/spine/chatbot/api/travis/Travis.java | 2 +- .../java/io/spine/chatbot/server/github/GitHubContext.java | 4 ++-- .../spine/chatbot/server/google/chat/GoogleChatContext.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index ee300d2d..46123be6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -57,7 +57,7 @@ private GoogleChat(HangoutsChat chat) { * *

The client is backed by {@link HangoutsChat} API. */ - public static GoogleChatClient instance() { + public static GoogleChatClient newInstance() { return new GoogleChat(hangoutsChat()); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index 33530793..9fd9278e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -55,7 +55,7 @@ private Travis(String token) { /** * Creates a new Travis client with the default secure Travis token. */ - public static TravisClient instance() { + public static TravisClient newInstance() { return new Travis(Secrets.travisToken()); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index dd02ddfb..2ee5459e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -90,11 +90,11 @@ public Builder setTravis(TravisClient travisClient) { * Finishes configuration of the context and builds a new instance. * *

If the {@link #travisClient} was not explicitly configured, uses the - * {@link Travis#instance() default} client. + * {@link Travis#newInstance() default} client. */ public GitHubContext build() { if (travisClient == null) { - travisClient = Travis.instance(); + travisClient = Travis.newInstance(); } return new GitHubContext(travisClient); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index e71383d9..ca9e50ef 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -95,7 +95,7 @@ public Builder setGoogleChatClient(GoogleChatClient googleChatClient) { */ public GoogleChatContext build() { if (googleChatClient == null) { - googleChatClient = GoogleChat.instance(); + googleChatClient = GoogleChat.newInstance(); } return new GoogleChatContext(googleChatClient); } From a13a9998dae8654e369cdd8eac6667637511d797 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 21:04:26 +0300 Subject: [PATCH 251/492] Extract logger --- .../java/io/spine/chatbot/api/google/chat/GoogleChat.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 46123be6..32796baa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -64,11 +64,12 @@ public static GoogleChatClient newInstance() { @Override public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread) { var repoSlug = buildState.getRepositorySlug(); - _debug().log("Building state update message for repository `%s`.", repoSlug); + var debug = _debug(); + debug.log("Building state update message for repository `%s`.", repoSlug); var message = buildStateMessage(buildState, thread); - _debug().log("Sending state update message for repository `%s`.", repoSlug); + debug.log("Sending state update message for repository `%s`.", repoSlug); var result = sendMessage(buildState.getGoogleChatSpace(), message); - _debug().log( + debug.log( "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", result.getName(), repoSlug, result.getThread() .getName() From 19938d72d05acbc95df50466d33f58569d908aab Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 22 Jun 2020 21:05:34 +0300 Subject: [PATCH 252/492] Drop repetitive inheritance comment --- .../io/spine/chatbot/api/travis/JsonProtoBodyHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java index 0d7d51e3..88ff3847 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java @@ -31,9 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** - * A {@link HttpResponse.BodyHandler BodyHandler} for JSON Protobuf messages. - * - *

The handler converts input JSON strings into the Protobuf messages relying on the + * The handler converts input JSON strings into the Protobuf messages relying on the * Spine {@link Json} conversion functionality. * * @param From 5f4f3aa6fad33074123c6bcb6c76d53d32194f11 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 10:37:24 +0300 Subject: [PATCH 253/492] Drop Google Chat part of the doc --- .../io/spine/chatbot/api/google/chat/BuildStateUpdates.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index a8945cf0..97196d6c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -39,7 +39,7 @@ import static io.spine.validate.Validate.checkValid; /** - * A Google Chat utility class that creates {@link BuildState} update messages. + * A utility class that creates {@link BuildState} update messages. */ final class BuildStateUpdates { From 375ae8bd7f970e51eee4139b1913afa348d947a9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 10:38:44 +0300 Subject: [PATCH 254/492] Cleanup doc --- google-chat-bot/src/main/java/io/spine/net/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/net/package-info.java b/google-chat-bot/src/main/java/io/spine/net/package-info.java index fde4c7f5..456c6290 100644 --- a/google-chat-bot/src/main/java/io/spine/net/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/net/package-info.java @@ -19,7 +19,7 @@ */ /** - * This package Spine .net utilities. + * This package contains utilities for working with network-related messages. */ @CheckReturnValue @ParametersAreNonnullByDefault From 981c004854a4ff3eb25111adb5e207e291cb5b76 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 10:40:01 +0300 Subject: [PATCH 255/492] Mention the entry point and env config --- .../src/main/java/io/spine/chatbot/package-info.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java index b417bbbf..f5a9cb05 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java @@ -19,7 +19,8 @@ */ /** - * This contains package Spine's Google Chat Bot application and environment configurations. + * This contains package the application {@link io.spine.chatbot.Application entry point} + * and the {@link io.spine.chatbot.ChatBotServerEnvironment environment} configurations. */ @CheckReturnValue @ParametersAreNonnullByDefault From 37a8ed0cfd0f7842bb883f693914ccd61ae73ba0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 10:41:39 +0300 Subject: [PATCH 256/492] Drop `idOf` suffix from Identifiers --- .../server/github/GitHubIdentifier.java | 4 ++-- .../server/github/SpineOrgInitProcess.java | 8 ++++---- .../google/chat/GoogleChatIdentifier.java | 6 +++--- .../google/chat/IncomingEventsHandler.java | 8 ++++---- .../server/google/chat/ThreadChatProcess.java | 12 +++++------ .../google/chat/ThreadChatRepository.java | 4 ++-- .../github/OrganizationAggregateTest.java | 4 ++-- .../server/github/RepoBuildProcessTest.java | 8 ++++---- .../github/RepositoryAggregateTest.java | 8 ++++---- .../github/SpineOrgInitProcessTest.java | 2 +- .../google/chat/GoogleChatIdentifierTest.java | 20 +++++++++---------- .../chat/IncomingEventsHandlerTest.java | 8 ++++---- .../google/chat/SpaceAggregateTest.java | 4 ++-- .../google/chat/ThreadAggregateTest.java | 16 +++++++-------- .../google/chat/ThreadChatProcessTest.java | 16 +++++++-------- 15 files changed, 64 insertions(+), 64 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java index 514a4a03..e2ab6b46 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java @@ -37,7 +37,7 @@ private GitHubIdentifier() { /** * Creates a new {@link OrganizationId} out of the specified {@code name}. */ - public static OrganizationId organizationIdOf(String name) { + public static OrganizationId organization(String name) { return OrganizationId .newBuilder() .setValue(name) @@ -47,7 +47,7 @@ public static OrganizationId organizationIdOf(String name) { /** * Creates a new {@link RepositoryId} out of the specified {@code slug}. */ - public static RepositoryId repositoryIdOf(String slug) { + public static RepositoryId repository(String slug) { return RepositoryId .newBuilder() .setValue(slug) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 16cb5059..d7b9d1aa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -38,8 +38,8 @@ import io.spine.server.procman.ProcessManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; -import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organization; +import static io.spine.chatbot.server.github.GitHubIdentifier.repository; import static io.spine.net.Urls.githubRepoUrlFor; import static io.spine.net.Urls.travisRepoUrlFor; import static io.spine.net.Urls.urlOfSpec; @@ -61,7 +61,7 @@ final class SpineOrgInitProcess ); /** The initialization process ID. **/ - static final OrganizationId SPINE_ORGANIZATION = organizationIdOf(SPINE_ORG); + static final OrganizationId SPINE_ORGANIZATION = organization(SPINE_ORG); @LazyInit private @MonotonicNonNull TravisClient travisClient; @@ -102,7 +102,7 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o .newBuilder() .setOrganization(orgId) .setGithubUrl(githubRepoUrlFor(slug)) - .setId(repositoryIdOf(slug)) + .setId(repository(slug)) .setName(repo.getName()) .setTravisCiUrl(travisRepoUrlFor(slug)) .vBuild(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java index d5c8d16f..960cfa3e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java @@ -40,7 +40,7 @@ private GoogleChatIdentifier() { /** * Creates a new {@link ThreadId} out of the specified {@code value}. */ - public static ThreadId threadIdOf(String value) { + public static ThreadId thread(String value) { checkNotNull(value); return ThreadId .newBuilder() @@ -51,7 +51,7 @@ public static ThreadId threadIdOf(String value) { /** * Creates a new {@link SpaceId} out of the specified {@code value}. */ - public static SpaceId spaceIdOf(String value) { + public static SpaceId space(String value) { checkNotNull(value); return SpaceId .newBuilder() @@ -62,7 +62,7 @@ public static SpaceId spaceIdOf(String value) { /** * Creates a new {@link MessageId} out of the specified {@code value}. */ - public static MessageId messageIdOf(String value) { + public static MessageId message(String value) { checkNotNull(value); return MessageId .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 6bf52c1f..a0e0e74e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -31,7 +31,7 @@ import io.spine.server.model.Nothing; import io.spine.server.tuple.EitherOf4; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; /** * Google Chat incoming events reactor. @@ -60,7 +60,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin case MESSAGE: _info().log("New user message received."); var message = chatEvent.getMessage(); - var messageId = GoogleChatIdentifier.messageIdOf(message.getName()); + var messageId = GoogleChatIdentifier.message(message.getName()); var messageReceived = MessageReceived .newBuilder() .setEvent(chatEvent) @@ -74,7 +74,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin var addedToSpace = BotAddedToSpace .newBuilder() .setEvent(chatEvent) - .setSpaceId(spaceIdOf(toSpace.getName())) + .setSpaceId(space(toSpace.getName())) .vBuild(); return EitherOf4.withA(addedToSpace); case REMOVED_FROM_SPACE: @@ -84,7 +84,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin var removedFromSpace = BotRemovedFromSpace .newBuilder() .setEvent(chatEvent) - .setSpaceId(spaceIdOf(fromSpace.getName())) + .setSpaceId(space(fromSpace.getName())) .vBuild(); return EitherOf4.withB(removedFromSpace); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 8915d914..0ef6e91e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -40,9 +40,9 @@ import java.util.Optional; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; /** @@ -86,9 +86,9 @@ Pair> on(@External BuildRecovered e) { private Pair> processBuildStateUpdate(BuildState buildState, RepositoryId repositoryId) { var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, state().getThread()); - var messageId = messageIdOf(sentMessage.getName()); - var threadId = threadIdOf(repositoryId.getValue()); - var spaceId = spaceIdOf(buildState.getGoogleChatSpace()); + var messageId = message(sentMessage.getName()); + var threadId = thread(repositoryId.getValue()); + var spaceId = space(buildState.getGoogleChatSpace()); var messageCreated = MessageCreated .newBuilder() .setId(messageId) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 997db33d..0e529085 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -34,7 +34,7 @@ import java.util.Set; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.server.route.EventRoute.withId; /** @@ -68,7 +68,7 @@ private static class RepositoryEventRoute implem @Override public Set apply(M event, EventContext context) { var repositoryId = event.getId(); - return withId(threadIdOf(repositoryId.getValue())); + return withId(thread(repositoryId.getValue())); } } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 8c330046..292505ce 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -30,7 +30,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") @@ -40,7 +40,7 @@ final class OrganizationAggregateTest extends GitHubContextAwareTest { @DisplayName("register an organization") final class Register { - private final OrganizationId organizationId = organizationIdOf("TestOrganization"); + private final OrganizationId organizationId = organization("TestOrganization"); private final Url githubUrl = urlOfSpec("https://github.com/TestOrganization"); private final Url travisCiUrl = urlOfSpec("https://travis-ci.com/TestOrganization"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 4b35084b..782d2898 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -39,15 +39,15 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; -import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organization; +import static io.spine.chatbot.server.github.GitHubIdentifier.repository; import static io.spine.chatbot.server.github.RepoBuildProcess.buildStateFrom; @DisplayName("RepoBuildProcess should") final class RepoBuildProcessTest extends GitHubContextAwareTest { - private static final OrganizationId orgId = organizationIdOf("SpineEventEngine"); - private static final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/web"); + private static final OrganizationId orgId = organization("SpineEventEngine"); + private static final RepositoryId repositoryId = repository("SpineEventEngine/web"); private static final String chatSpace = "spaces/1245wrq"; @Test diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 1c38fb94..552c603b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -31,8 +31,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organizationIdOf; -import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.organization; +import static io.spine.chatbot.server.github.GitHubIdentifier.repository; import static io.spine.net.Urls.urlOfSpec; @DisplayName("RepositoryAggregate should") @@ -42,8 +42,8 @@ final class RepositoryAggregateTest extends GitHubContextAwareTest { @DisplayName("register a repository") final class Register { - private final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/base"); - private final OrganizationId organizationId = organizationIdOf("SpineEventEngine"); + private final RepositoryId repositoryId = repository("SpineEventEngine/base"); + private final OrganizationId organizationId = organization("SpineEventEngine"); private final Url githubUrl = urlOfSpec("https://github.com/SpineEventEngine/base"); private final Url travisCiUrl = diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index b9077369..6f00cde6 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -40,7 +40,7 @@ final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @DisplayName("perform initialization of watched spine resources") final class Init { - private final SpaceId spaceId = GoogleChatIdentifier.spaceIdOf("spaces/qjwrp1441"); + private final SpaceId spaceId = GoogleChatIdentifier.space("spaces/qjwrp1441"); private final Repository repository = Repository .newBuilder() .setId(123312L) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java index 57cf9d08..ade3cdfc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java @@ -35,8 +35,8 @@ import java.util.stream.Stream; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; @DisplayName("GoogleChatIdentifier should") @@ -57,14 +57,14 @@ final class NotAcceptInvalid { @MethodSource("spaceIdsSource") @DisplayName("space IDs") void spaceIds(String value) { - Assertions.assertThrows(ValidationException.class, () -> spaceIdOf(value)); + Assertions.assertThrows(ValidationException.class, () -> space(value)); } @ParameterizedTest @MethodSource("messageIdsSource") @DisplayName("space IDs") void messageIds(String value) { - Assertions.assertThrows(ValidationException.class, () -> messageIdOf(value)); + Assertions.assertThrows(ValidationException.class, () -> message(value)); } @SuppressWarnings("unused") // method is used as parameterized test source @@ -82,17 +82,17 @@ private Stream messageIdsSource() { @DisplayName("create space ID") void createSpaceId() { var spaceId = "spaces/qew21466"; - assertThat(spaceIdOf(spaceId)).isEqualTo(SpaceId.newBuilder() - .setValue(spaceId) - .buildPartial()); + assertThat(space(spaceId)).isEqualTo(SpaceId.newBuilder() + .setValue(spaceId) + .buildPartial()); } @Test @DisplayName("create message ID") void createMessageId() { var messageId = "spaces/qew21466/messages/123112111"; - assertThat(messageIdOf(messageId)).isEqualTo(MessageId.newBuilder() - .setValue(messageId) - .buildPartial()); + assertThat(message(messageId)).isEqualTo(MessageId.newBuilder() + .setValue(messageId) + .buildPartial()); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index 51d0d1d0..8cb34ad4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -33,14 +33,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @DisplayName("IncomingEventsHandler should") final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { - private static final SpaceId spaceId = spaceIdOf("spaces/fqeq325661a"); - private static final MessageId messageId = messageIdOf("spaces/fqeq325661a/messages/422"); + private static final SpaceId spaceId = space("spaces/fqeq325661a"); + private static final MessageId messageId = message("spaces/fqeq325661a/messages/422"); @Test @DisplayName("add bot to a space") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index b71baba9..42aa240f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -34,12 +34,12 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @DisplayName("SpaceAggregate should") final class SpaceAggregateTest extends GoogleChatContextAwareTest { - private static final SpaceId spaceId = spaceIdOf("spaces/poqwdpQ21"); + private static final SpaceId spaceId = space("spaces/poqwdpQ21"); private static final String displayName = "Spine Developers"; @Nested diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index f8b726e2..fc9d2937 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -34,9 +34,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadAggregate should") @@ -46,8 +46,8 @@ final class ThreadAggregateTest extends GoogleChatContextAwareTest { @DisplayName("initialize a thread") final class InitThread { - private final ThreadId threadId = threadIdOf("SpineEventEngine/base"); - private final SpaceId spaceId = spaceIdOf("spaces/qpojdwpiq1241"); + private final ThreadId threadId = thread("SpineEventEngine/base"); + private final SpaceId spaceId = space("spaces/qpojdwpiq1241"); private final ThreadResource threadResource = threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); @@ -92,10 +92,10 @@ void settingState() { @DisplayName("add created message") final class AddMessage { - private final ThreadId threadId = threadIdOf("SpineEventEngine/base"); - private final SpaceId spaceId = spaceIdOf("spaces/qpojdwpiq1241"); + private final ThreadId threadId = thread("SpineEventEngine/base"); + private final SpaceId spaceId = space("spaces/qpojdwpiq1241"); private final MessageId messageId = - messageIdOf("spaces/qpojdwpiq1241/messages/dqpwjpop12"); + message("spaces/qpojdwpiq1241/messages/dqpwjpop12"); private final ThreadResource threadResource = threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 48dfcd38..0c1e0034 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -38,10 +38,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.repositoryIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.messageIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.spaceIdOf; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.threadIdOf; +import static io.spine.chatbot.server.github.GitHubIdentifier.repository; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; @DisplayName("ThreadChatProcess should") @@ -81,10 +81,10 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, private abstract static class BuildStateChanged extends GoogleChatContextAwareTest { - private final RepositoryId repositoryId = repositoryIdOf("SpineEventEngine/money"); - private final ThreadId threadId = threadIdOf(repositoryId.getValue()); + private final RepositoryId repositoryId = repository("SpineEventEngine/money"); + private final ThreadId threadId = thread(repositoryId.getValue()); private final String googleChatSpace = "spaces/1241pjwqe"; - private final SpaceId spaceId = spaceIdOf(googleChatSpace); + private final SpaceId spaceId = space(googleChatSpace); private final String buildNumber = "551"; private final Thread newThread = new Thread().setName("spaces/1241pjwqe/threads/k12d1o2r1"); private final Message sentMessage = new Message() @@ -115,7 +115,7 @@ abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, void producingEvents() { var messageCreated = MessageCreated .newBuilder() - .setId(messageIdOf(sentMessage.getName())) + .setId(message(sentMessage.getName())) .setThreadId(threadId) .setSpaceId(spaceId) .vBuild(); From 5f965fe124f1eb5fffddb01afd3630265f375299 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 10:45:27 +0300 Subject: [PATCH 257/492] Use OrgId for logs and URLs --- .../server/github/SpineOrgInitProcess.java | 15 +++++++------- .../src/main/java/io/spine/net/Urls.java | 20 +++++++++---------- .../src/test/java/io/spine/net/UrlsTest.java | 8 ++++---- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index d7b9d1aa..49026c5d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -40,8 +40,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.net.Urls.githubRepoUrlFor; -import static io.spine.net.Urls.travisRepoUrlFor; +import static io.spine.net.Urls.githubUrlFor; +import static io.spine.net.Urls.travisUrlFor; import static io.spine.net.Urls.urlOfSpec; /** @@ -101,21 +101,22 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o return RegisterRepository .newBuilder() .setOrganization(orgId) - .setGithubUrl(githubRepoUrlFor(slug)) + .setGithubUrl(githubUrlFor(slug)) .setId(repository(slug)) .setName(repo.getName()) - .setTravisCiUrl(travisRepoUrlFor(slug)) + .setTravisCiUrl(travisUrlFor(slug)) .vBuild(); } private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, String spaceName) { - _info().log("Registering `Spine Event Engine` organization."); + var orgSlug = spineOrgId.getValue(); + _info().log("Registering `%s` organization.", orgSlug); return RegisterOrganization .newBuilder() .setName("Spine Event Engine") .setWebsiteUrl(urlOfSpec("https://spine.io/")) - .setTravisCiUrl(urlOfSpec("https://travis-ci.com/github/SpineEventEngine")) - .setGithubUrl(urlOfSpec("https://github.com/SpineEventEngine")) + .setTravisCiUrl(travisUrlFor(orgSlug)) + .setGithubUrl(githubUrlFor(orgSlug)) .setId(spineOrgId) .setGoogleChatSpace(spaceName) .vBuild(); diff --git a/google-chat-bot/src/main/java/io/spine/net/Urls.java b/google-chat-bot/src/main/java/io/spine/net/Urls.java index 82a4c781..85f93861 100644 --- a/google-chat-bot/src/main/java/io/spine/net/Urls.java +++ b/google-chat-bot/src/main/java/io/spine/net/Urls.java @@ -51,27 +51,25 @@ public static Url urlOfSpec(String spec) { */ public static Url travisBuildUrlFor(String repoSlug, long buildId) { checkNotNull(repoSlug); - var spec = format("%s/%s/builds/%d", - TRAVIS_GITHUB_ENDPOINT, repoSlug, buildId); + var spec = format("%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, repoSlug, buildId); return urlOfSpec(spec); } /** - * Creates a new Travis CI repository URL. + * Creates a new Travis CI URL. */ - public static Url travisRepoUrlFor(String repoSlug) { - checkNotNull(repoSlug); - var spec = format("%s/%s", - TRAVIS_GITHUB_ENDPOINT, repoSlug); + public static Url travisUrlFor(String slug) { + checkNotNull(slug); + var spec = format("%s/%s", TRAVIS_GITHUB_ENDPOINT, slug); return urlOfSpec(spec); } /** - * Creates a new GitHub repository URL. + * Creates a new GitHub URL. */ - public static Url githubRepoUrlFor(String repoSlug) { - checkNotNull(repoSlug); - var spec = format("%s/%s", GITHUB, repoSlug); + public static Url githubUrlFor(String slug) { + checkNotNull(slug); + var spec = format("%s/%s", GITHUB, slug); return urlOfSpec(spec); } } diff --git a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java index 662d4032..09588d9b 100644 --- a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java @@ -26,9 +26,9 @@ import org.junit.jupiter.api.Test; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.net.Urls.githubRepoUrlFor; +import static io.spine.net.Urls.githubUrlFor; import static io.spine.net.Urls.travisBuildUrlFor; -import static io.spine.net.Urls.travisRepoUrlFor; +import static io.spine.net.Urls.travisUrlFor; import static io.spine.net.Urls.urlOfSpec; @DisplayName("Urls should") @@ -48,7 +48,7 @@ final class Compose { @DisplayName("Travis CI repository page") @Test void travisRepo() { - assertThat(travisRepoUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( + assertThat(travisUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( "https://travis-ci.com/github/SpineEventEngine/chat-bot" )); } @@ -64,7 +64,7 @@ void travisBuild() { @DisplayName("GitHub repository page") @Test void githubRepo() { - assertThat(githubRepoUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( + assertThat(githubUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( "https://github.com/SpineEventEngine/chat-bot" )); } From 85d2ae789ea7d5d1205ffbe05fc079bcb44c2fc6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 10:46:11 +0300 Subject: [PATCH 258/492] Use string constant directly --- .../spine/chatbot/server/github/SpineOrgInitProcess.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 49026c5d..51049081 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -109,14 +109,13 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o } private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, String spaceName) { - var orgSlug = spineOrgId.getValue(); - _info().log("Registering `%s` organization.", orgSlug); + _info().log("Registering `%s` organization.", SPINE_ORG); return RegisterOrganization .newBuilder() .setName("Spine Event Engine") .setWebsiteUrl(urlOfSpec("https://spine.io/")) - .setTravisCiUrl(travisUrlFor(orgSlug)) - .setGithubUrl(githubUrlFor(orgSlug)) + .setTravisCiUrl(travisUrlFor(SPINE_ORG)) + .setGithubUrl(githubUrlFor(SPINE_ORG)) .setId(spineOrgId) .setGoogleChatSpace(spaceName) .vBuild(); From f065a46fe6eb68221ebfa8409ef7f61aa9f6d193 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:28:34 +0300 Subject: [PATCH 259/492] Move docs to the class level and extract help methods. --- .../google/chat/IncomingEventsHandler.java | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index a0e0e74e..7c0677b5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -31,62 +31,43 @@ import io.spine.server.model.Nothing; import io.spine.server.tuple.EitherOf4; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; /** * Google Chat incoming events reactor. * - *

Processes {@link ChatEvent}s received by the ChatBot. + *

Processes incoming {@link ChatEvent} message and emits one of the following domain events: + * + *

    + *
  • {@link BotAddedToSpace} — the ChatBot is added to a Google Chat space; + *
  • {@link BotRemovedFromSpace} — the ChatBot is removed from the Google Chat space; + *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user + * within a Google Chat space. + *
+ * + *

If the bot receives a chat event with a not supported currently event type, + * {@link Nothing} is emitted. */ final class IncomingEventsHandler extends AbstractEventReactor implements Logging { - /** - * Processes incoming {@link ChatEvent} message and emits one of the following domain events: - * - *

    - *
  • {@link BotAddedToSpace} — the ChatBot is added to a Google Chat space; - *
  • {@link BotRemovedFromSpace} — the ChatBot is removed from the Google Chat space; - *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user - * within a Google Chat space. - *
- * - *

If the bot receives a chat event with a not supported currently event type, - * {@link Nothing} is emitted. - */ @React EitherOf4 on(@External ChatEvent chatEvent) { switch (chatEvent.getType()) { case MESSAGE: _info().log("New user message received."); - var message = chatEvent.getMessage(); - var messageId = GoogleChatIdentifier.message(message.getName()); - var messageReceived = MessageReceived - .newBuilder() - .setEvent(chatEvent) - .setMessageId(messageId) - .vBuild(); - return EitherOf4.withC(messageReceived); + return EitherOf4.withC(messageReceived(chatEvent)); case ADDED_TO_SPACE: var toSpace = chatEvent.getSpace(); _info().log("ChatBot added to space `%s` (%s).", toSpace.getDisplayName(), toSpace.getName()); - var addedToSpace = BotAddedToSpace - .newBuilder() - .setEvent(chatEvent) - .setSpaceId(space(toSpace.getName())) - .vBuild(); - return EitherOf4.withA(addedToSpace); + return EitherOf4.withA(botAddedToSpace(chatEvent)); case REMOVED_FROM_SPACE: var fromSpace = chatEvent.getSpace(); _info().log("ChatBot removed from space `%s` (%s).", fromSpace.getDisplayName(), fromSpace.getName()); - var removedFromSpace = BotRemovedFromSpace - .newBuilder() - .setEvent(chatEvent) - .setSpaceId(space(fromSpace.getName())) - .vBuild(); - return EitherOf4.withB(removedFromSpace); + return EitherOf4.withB(botRemovedFromSpace(chatEvent)); case CARD_CLICKED: case UNRECOGNIZED: @@ -96,4 +77,31 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin return EitherOf4.withD(nothing()); } } + + private static BotRemovedFromSpace botRemovedFromSpace(ChatEvent chatEvent) { + var space = chatEvent.getSpace(); + return BotRemovedFromSpace + .newBuilder() + .setEvent(chatEvent) + .setSpaceId(space(space.getName())) + .vBuild(); + } + + private static BotAddedToSpace botAddedToSpace(ChatEvent chatEvent) { + var space = chatEvent.getSpace(); + return BotAddedToSpace + .newBuilder() + .setEvent(chatEvent) + .setSpaceId(space(space.getName())) + .vBuild(); + } + + private static MessageReceived messageReceived(ChatEvent chatEvent) { + var message = chatEvent.getMessage(); + return MessageReceived + .newBuilder() + .setEvent(chatEvent) + .setMessageId(message(message.getName())) + .vBuild(); + } } From 3298c63e4b1010b2d4a2bef816640d4d77c7184c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:31:28 +0300 Subject: [PATCH 260/492] Rename API clients. --- .../spine/chatbot/server/github/RepoBuildProcess.java | 8 ++++---- .../chatbot/server/github/RepoBuildRepository.java | 2 +- .../chatbot/server/google/chat/ThreadChatProcess.java | 8 ++++---- .../server/google/chat/ThreadChatRepository.java | 10 ++++++---- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 3e1c615c..77ba987e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -74,7 +74,7 @@ final class RepoBuildProcess implements Logging { @LazyInit - private @MonotonicNonNull TravisClient travisClient; + private @MonotonicNonNull TravisClient client; /** * Checks the repository build state and propagates the respective events. @@ -87,7 +87,7 @@ EitherOf3 handle(CheckRepositoryBuild throws NoBuildsFound { var repositoryId = c.getId(); _info().log("Checking build status for repository `%s`.", repositoryId.getValue()); - var branchBuild = travisClient.execute(BuildsQuery.forRepo(repositoryId.getValue())); + var branchBuild = client.execute(BuildsQuery.forRepo(repositoryId.getValue())); if (isDefault(branchBuild.getLastBuild())) { _warn().log("No builds found for the repository `%s`.", repositoryId.getValue()); throw NoBuildsFound @@ -200,7 +200,7 @@ private static BuildState.Commit from(Commit commit) { .vBuild(); } - void setTravisClient(TravisClient travisClient) { - this.travisClient = travisClient; + void setClient(TravisClient client) { + this.client = client; } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java index d0c8bcdd..8423e290 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java @@ -40,6 +40,6 @@ final class RepoBuildRepository @Override protected void configure(RepoBuildProcess processManager) { super.configure(processManager); - processManager.setTravisClient(travisClient); + processManager.setClient(travisClient); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 0ef6e91e..79de14a8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -52,7 +52,7 @@ final class ThreadChatProcess extends ProcessManager> on(@External BuildRecovered e) { private Pair> processBuildStateUpdate(BuildState buildState, RepositoryId repositoryId) { - var sentMessage = googleChatClient.sendBuildStateUpdate(buildState, state().getThread()); + var sentMessage = client.sendBuildStateUpdate(buildState, state().getThread()); var messageId = message(sentMessage.getName()); var threadId = thread(repositoryId.getValue()); var spaceId = space(buildState.getGoogleChatSpace()); @@ -117,7 +117,7 @@ private boolean shouldCreateThread() { return Messages.isDefault(state().getThread()); } - void setGoogleChatClient(GoogleChatClient googleChatClient) { - this.googleChatClient = googleChatClient; + void setClient(GoogleChatClient client) { + this.client = client; } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 0e529085..062f4511 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -40,7 +40,8 @@ /** * The repository for {@link ThreadChatProcess}es. */ -final class ThreadChatRepository extends ProcessManagerRepository { +final class ThreadChatRepository + extends ProcessManagerRepository { private final GoogleChatClient googleChatClient; @@ -58,12 +59,13 @@ protected void setupEventRouting(EventRouting routing) { @Override protected void configure(ThreadChatProcess processManager) { - processManager.setGoogleChatClient(googleChatClient); + processManager.setClient(googleChatClient); } - private static class RepositoryEventRoute implements EventRoute { + private static class RepositoryEventRoute + implements EventRoute { - private static final long serialVersionUID = 5147803958347083018L; + private static final long serialVersionUID = 0L; @Override public Set apply(M event, EventContext context) { From 3e67870a4e043af901bb7a7e3d8af5e21663c233 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:31:36 +0300 Subject: [PATCH 261/492] Add method-level doc --- .../chatbot/server/google/chat/IncomingEventsHandler.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 7c0677b5..d6fe951a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -51,6 +51,11 @@ */ final class IncomingEventsHandler extends AbstractEventReactor implements Logging { + /** + * Processes incoming external {@link ChatEvent}. + * + *

If the event type is not supported, returns {@link #nothing() nothing}. + */ @React EitherOf4 on(@External ChatEvent chatEvent) { From ee059d599d251d4af61b32e1c208a7e867978b67 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:36:26 +0300 Subject: [PATCH 262/492] Drop extra empty lines --- .../proto/spine/chatbot/github/repository_build_commands.proto | 1 - .../proto/spine/chatbot/github/repository_build_events.proto | 1 - 2 files changed, 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 85139970..2cb72594 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -30,7 +30,6 @@ option java_outer_classname = "RepositoryBuildCommandsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; - import "spine/chatbot/github/identifiers.proto"; // Check repository CI build state command. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 4e894f4a..84b67473 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -32,7 +32,6 @@ option java_generate_equals_and_hash = true; option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; - import "spine/chatbot/github/identifiers.proto"; import "spine/chatbot/github/repository_build.proto"; From 0478316bf218a873f6763c53498fe79386fc0d59 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:36:45 +0300 Subject: [PATCH 263/492] Add missing comma --- .../main/proto/spine/chatbot/github/repository_commands.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 732025dc..482284c5 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -48,6 +48,6 @@ message RegisterRepository { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4 [(required) = true]; - // ID of the organization the repository is related to if any. + // ID of the organization the repository is related to, if any. OrganizationId organization = 5; } From b7fca63af6cfce6f0b89eb19741cf1c3ced80b8a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:48:33 +0300 Subject: [PATCH 264/492] Drop `id` prefix usage and cleanup docs. --- .../proto/spine/chatbot/github/organization.proto | 2 +- .../chatbot/github/organization_commands.proto | 2 +- .../chatbot/github/organization_events.proto | 2 +- .../spine/chatbot/github/organization_init.proto | 2 +- .../github/organization_init_commands.proto | 2 +- .../github/organization_repositories.proto | 2 +- .../proto/spine/chatbot/github/repository.proto | 2 +- .../spine/chatbot/github/repository_build.proto | 2 +- .../github/repository_build_commands.proto | 2 +- .../chatbot/github/repository_build_events.proto | 8 ++++---- .../github/repository_build_rejections.proto | 2 +- .../chatbot/github/repository_commands.proto | 2 +- .../spine/chatbot/github/repository_events.proto | 2 +- .../spine/chatbot/google/chat/chat_events.proto | 14 +++++++------- .../spine/chatbot/google/chat/identifiers.proto | 6 +++--- .../chat/incoming/incoming_chat_events.proto | 6 +++--- .../chat/incoming/incoming_chat_messages.proto | 15 ++++++++------- .../proto/spine/chatbot/google/chat/space.proto | 4 ++-- .../chatbot/google/chat/space_commands.proto | 4 ++-- .../spine/chatbot/google/chat/space_events.proto | 4 ++-- .../proto/spine/chatbot/google/chat/thread.proto | 10 +++++----- .../spine/chatbot/google/chat/thread_chat.proto | 8 ++++---- .../spine/chatbot/google/chat/thread_events.proto | 10 +++++----- .../main/proto/spine/chatbot/travis/travis.proto | 4 ++-- 24 files changed, 59 insertions(+), 58 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index c847ece0..ee88896b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -39,7 +39,7 @@ message Organization { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - OrganizationId id = 1; + OrganizationId organization = 1; // Name of the GitHub organization. string name = 2; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 28266364..e67f4bfc 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -37,7 +37,7 @@ import "spine/chatbot/github/identifiers.proto"; // An organization registration command. message RegisterOrganization { - OrganizationId id = 1 [(required) = true]; + OrganizationId organization = 1 [(required) = true]; // Name of the GitHub organization. string name = 2 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index ff8b46a3..a4c51ef4 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -37,7 +37,7 @@ import "spine/chatbot/github/identifiers.proto"; // An organization is registered. message OrganizationRegistered { - OrganizationId id = 1 [(required) = true]; + OrganizationId organization = 1 [(required) = true]; // Name of the GitHub organization. string name = 2 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index b5cc3db9..477eef9c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -42,7 +42,7 @@ message OrganizationInit { option (entity).visibility = FULL; // The ID of the organization for which the initialization is performed. - OrganizationId id = 1; + OrganizationId organization = 1; // Name of the Google Chat space associated with the organization in form `spaces/`. string google_chat_space = 2; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index b937fe34..b1fd3d8c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -36,7 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; message InitializeOrganization { // ID of the organization to perform initialization for. - OrganizationId id = 1 [(required) = true]; + OrganizationId organization = 1 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. string google_chat_space = 2 [(required) = true, (pattern).regex = "spaces/.+"]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 6bfd28fd..1c0b1b05 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -37,7 +37,7 @@ message OrganizationRepositories { option (entity).kind = PROJECTION; option (entity).visibility = FULL; - OrganizationId id = 1; + OrganizationId organization = 1; // Linked organization repositories. repeated RepositoryId repositories = 2; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index a8dec37e..506f0a16 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -39,7 +39,7 @@ message Repository { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - RepositoryId id = 1; + RepositoryId repository = 1; // Name of the repository. string name = 2; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index b0df9197..fc46e682 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -42,7 +42,7 @@ message RepositoryBuild { option (entity).kind = PROCESS_MANAGER; option (entity).visibility = FULL; - RepositoryId id = 1; + RepositoryId repository = 1; // Time of the last status check. google.protobuf.Timestamp last_status_check = 2; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 2cb72594..356a2bee 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -36,7 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; message CheckRepositoryBuild { // ID of the repository to perform a check for. - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; // ID of the organization the repository belongs to. OrganizationId organization = 2 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 84b67473..5027b709 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -38,7 +38,7 @@ import "spine/chatbot/github/repository_build.proto"; // The build has failed for a repository. message BuildFailed { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; // The change of the build state. BuildStateChange change = 2; @@ -47,7 +47,7 @@ message BuildFailed { // The build has recovered from the failed state. message BuildRecovered { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; // The change of the build state. BuildStateChange change = 2; @@ -56,7 +56,7 @@ message BuildRecovered { // The build is stable and passing. message BuildStable { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; // The change of the build state. BuildStateChange change = 2; @@ -65,5 +65,5 @@ message BuildStable { // The build is stable and passing. message BuildInProgress { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto index 41e3337c..4bf53628 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto @@ -36,5 +36,5 @@ import "spine/chatbot/github/identifiers.proto"; // No CI builds found for the repository. message NoBuildsFound { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 482284c5..85a2325f 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -37,7 +37,7 @@ import "spine/chatbot/github/identifiers.proto"; // Register repository command. message RegisterRepository { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; // Name of the repository. string name = 2 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 5509c7b2..18316168 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -37,7 +37,7 @@ import "spine/chatbot/github/identifiers.proto"; // A repository is registered. message RepositoryRegistered { - RepositoryId id = 1 [(required) = true]; + RepositoryId repository = 1 [(required) = true]; // Name of the repository. string name = 2 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index 4721560d..00beebe3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -36,23 +36,23 @@ import "spine/chatbot/google/chat/thread.proto"; // A message created in the space. message MessageCreated { - MessageId id = 1 [(required) = true]; + MessageId message = 1 [(required) = true]; // ID of the space within which the message is created. - SpaceId space_id = 2 [(required) = true]; + SpaceId space = 2 [(required) = true]; // ID of the thread within which the message is created if created in a threaded space. - ThreadId thread_id = 3; + ThreadId thread = 3; } // A recently created message created a new thread. message ThreadCreated { - ThreadId id = 1 [(required) = true]; + ThreadId thread = 1 [(required) = true]; - // Google Chat thread. - ThreadResource thread = 2 [(required) = true]; + // Chat thread. + ThreadResource resource = 2 [(required) = true]; // ID of the space within with the thread is available. - SpaceId space_id = 3 [(required) = true]; + SpaceId space = 3 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto index e9823908..94d79846 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/identifiers.proto @@ -30,14 +30,14 @@ option java_outer_classname = "IdentifiersProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -// Hangouts Chat Space identifier. +// Chat Space identifier. message SpaceId { // Resource name of the space, in the form `spaces/`. string value = 1 [(required) = true, (pattern).regex = "spaces/.+"]; } -// Hangouts Chat Room Thread identifier. +// Chat Room Thread identifier. message ThreadId { // The thread identifier is linked to the topic discussed in the thread. @@ -48,7 +48,7 @@ message ThreadId { string value = 1 [(required) = true]; } -// Hangouts Chat Message identifier. +// Chat Message identifier. message MessageId { // Resource name of the message, in the form `spaces//messages/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto index 90f00e7a..74d760ff 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto @@ -13,7 +13,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/incoming/incoming_chat_messages.proto"; -// The ChatBot is added to a Google Chat space. +// The ChatBot is added to a Chat space. message BotAddedToSpace { // The ID of the Space to which the ChatBot is added. @@ -23,7 +23,7 @@ message BotAddedToSpace { ChatEvent event = 2; } -// The ChatBot is removed from the Google Chat space. +// The ChatBot is removed from the Chat space. message BotRemovedFromSpace { // The ID of the Space from which the ChatBot is removed. @@ -33,7 +33,7 @@ message BotRemovedFromSpace { ChatEvent event = 2; } -// The ChatBot received a new incoming Google Chat message. +// The ChatBot received a new incoming Chat message. message MessageReceived { // The ID of the new message. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index acde5031..5b762096 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -30,7 +30,7 @@ option java_outer_classname = "IncomingChatMessagesProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -// A Google Chat incoming event. +// A Chat incoming event. message ChatEvent { option (is).java_type = "io.spine.base.EventMessage"; @@ -42,9 +42,10 @@ message ChatEvent { string event_time = 2 [(required) = true]; // A secret value that bots can use to verify if a request is from Google. + // // The token is randomly generated by Google, remains static, and can be obtained from - // the Hangouts Chat API configuration page in the Cloud Console. Developers can - // revoke/regenerate it if needed from the same page. + // the Chat API configuration page in the Cloud Console. Developers can revoke/regenerate + // it if needed from the same page. // string token = 3; @@ -61,7 +62,7 @@ message ChatEvent { User user = 7 [(required) = true]; } -// A message in Hangouts Chat. +// A message in Chat. message Message { // Resource name, in the form "spaces/*/messages/*". @@ -82,7 +83,7 @@ message Message { // The thread the message belongs to. Thread thread = 6; - // A thread in Hangouts Chat. + // A thread in Chat. message Thread { // Resource name, in the form "spaces/*/threads/*". @@ -121,7 +122,7 @@ message Message { } } -// A room or DM in Hangouts Chat. +// A room or DM in Chat. message Space { // Resource name of the space, in the form "spaces/*". @@ -134,7 +135,7 @@ message Space { SpaceType type = 3; } -// A user in Hangouts Chat. +// A user in Chat. message User { // Resource name, in the format "users/*". diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 3d6dc45c..a266ae2b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -32,12 +32,12 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; -// A room or DM in Hangouts Chat. +// A room or DM in Chat. message Space { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - SpaceId id = 1; + SpaceId space = 1; // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 7c21b1b2..7d7d7f28 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -32,10 +32,10 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; -// Register Google Chat space command. +// Register Chat space command. message RegisterSpace { - SpaceId id = 1 [(required) = true]; + SpaceId space = 1 [(required) = true]; // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto index 27c8f116..abd5a294 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -32,10 +32,10 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; -// A new Google Chat space registered. +// A new Chat space registered. message SpaceRegistered { - SpaceId id = 1 [(required) = true]; + SpaceId space = 1 [(required) = true]; // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index 83d9e1b9..e25182ce 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -32,24 +32,24 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; -// A thread in Google Chat room. +// A thread in a Chat room. message Thread { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - ThreadId id = 1; + ThreadId thread = 1; // Resource name of the thread. - ThreadResource thread = 2; + ThreadResource resource = 2; // ID of the space within with the thread is available. - SpaceId space_id = 3; + SpaceId space = 3; // IDs of the messages posted by the bot to the thread. repeated MessageId messages = 4; } -// Google Chat Thread resource. +// Chat Thread resource. message ThreadResource { // Resource name of the thread, in the form `spaces//threads/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto index 0eced719..d6407adc 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -41,11 +41,11 @@ message ThreadChat { option (entity).kind = PROCESS_MANAGER; option (entity).visibility = FULL; - ThreadId id = 1; + ThreadId thread = 1; - // Google Chat thread. - ThreadResource thread = 2; + // Chat thread. + ThreadResource resource = 2; // ID of the space within with the thread is available. - SpaceId space_id = 3; + SpaceId space = 3; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index 9b534cab..bcece528 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -33,16 +33,16 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/thread.proto"; -// A Google Chat thread initialized. +// A Chat thread initialized. message ThreadInitialized { - ThreadId id = 1 [(required) = true]; + ThreadId thread = 1 [(required) = true]; - // Google Chat thread. - ThreadResource thread = 2 [(required) = true]; + // Chat thread. + ThreadResource resource = 2 [(required) = true]; // ID of the space within which the thread is available. - SpaceId space_id = 3 [(required) = true]; + SpaceId space = 3 [(required) = true]; } // A message added to the thead. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 19b4c7a9..c3236825 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -59,7 +59,7 @@ message Repository { string slug = 3; } -// The branch of a GitHub repository. +// The branch of a repository. message Branch { // Name of the git branch. @@ -119,7 +119,7 @@ message Build { // State of the previous build. string previous_state = 6; - // GitHub repository the build is associated with. + // The repository the build is associated with. Repository repository = 7; // The branch the build is associated with. From 713cec1bcadcc717a077e1f9777b5ad9009705e0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:51:14 +0300 Subject: [PATCH 265/492] drop `chat` part --- .../src/main/proto/spine/chatbot/google/chat/thread.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index e25182ce..cd277b8b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -32,7 +32,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; -// A thread in a Chat room. +// A thread in a room. message Thread { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; From f9d66f97d729adf365a343c394549e9ddba53601 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 11:52:44 +0300 Subject: [PATCH 266/492] Remove unused import --- .../src/main/proto/google/pubsub/v1/pubsub_push.proto | 1 - 1 file changed, 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto index 4d7466ae..2205e71d 100644 --- a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto +++ b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto @@ -10,7 +10,6 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "google/pubsub/v1/pubsub.proto"; -import "google/protobuf/timestamp.proto"; // Pubsub push message notification. message PubsubPushNotification { From dab3d1af92bdd93dca48553d3f9a3e396d7ac8ec Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 12:06:40 +0300 Subject: [PATCH 267/492] Rename identifiers --- .../chatbot/google/chat/incoming/incoming_chat_events.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto index 74d760ff..c9ea3892 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto @@ -17,7 +17,7 @@ import "spine/chatbot/google/chat/incoming/incoming_chat_messages.proto"; message BotAddedToSpace { // The ID of the Space to which the ChatBot is added. - SpaceId space_id = 1 [(required) = true]; + SpaceId space = 1 [(required) = true]; // The actual chat event message. ChatEvent event = 2; @@ -27,7 +27,7 @@ message BotAddedToSpace { message BotRemovedFromSpace { // The ID of the Space from which the ChatBot is removed. - SpaceId space_id = 1 [(required) = true]; + SpaceId space = 1 [(required) = true]; // The actual chat event message. ChatEvent event = 2; @@ -37,7 +37,7 @@ message BotRemovedFromSpace { message MessageReceived { // The ID of the new message. - MessageId message_id = 1 [(required) = true]; + MessageId message = 1 [(required) = true]; // The actual chat event message. ChatEvent event = 2; From cc6725fcd6a6d96081b5dedc53235537b03e094f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 12:22:19 +0300 Subject: [PATCH 268/492] Drop `id` usage --- .../main/proto/spine/chatbot/google/chat/thread_events.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index bcece528..d5adf3f7 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -48,8 +48,8 @@ message ThreadInitialized { // A message added to the thead. message MessageAdded { - MessageId id = 1 [(required) = true]; + MessageId message = 1 [(required) = true]; // ID of the thread to which the message is added. - ThreadId thread_id = 2 [(required) = true]; + ThreadId thread = 2 [(required) = true]; } From f947d1b4fc59775d5e7c68b4045c79272825a3b6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 12:31:05 +0300 Subject: [PATCH 269/492] Drop `ID` usage --- .../spine/chatbot/RepositoriesController.java | 8 +-- .../chatbot/client/ChatBotServerClient.java | 2 +- .../server/github/OrgReposProjection.java | 4 +- .../server/github/OrganizationAggregate.java | 2 +- .../server/github/RepoBuildProcess.java | 18 ++--- .../server/github/RepositoryAggregate.java | 5 +- .../server/github/RepositoryAware.java | 11 ++- .../server/github/RepositoryAwareEvent.java | 9 --- .../server/github/SpineOrgInitProcess.java | 14 ++-- .../google/chat/IncomingEventsHandler.java | 6 +- .../server/google/chat/SpaceAggregate.java | 10 +-- .../server/google/chat/SpaceRepository.java | 2 +- .../server/google/chat/ThreadAggregate.java | 19 ++--- .../server/google/chat/ThreadChatProcess.java | 48 ++++++------- .../google/chat/ThreadChatRepository.java | 4 +- .../server/google/chat/ThreadRepository.java | 4 +- .../server/google/chat/ThreadResources.java | 2 +- .../github/OrganizationAggregateTest.java | 15 ++-- .../server/github/RepoBuildProcessTest.java | 70 +++++++++---------- .../github/RepositoryAggregateTest.java | 37 +++++----- .../github/SpineOrgInitProcessTest.java | 4 +- .../chat/IncomingEventsHandlerTest.java | 6 +- .../google/chat/SpaceAggregateTest.java | 34 ++++----- .../google/chat/ThreadAggregateTest.java | 65 +++++++++-------- .../google/chat/ThreadChatProcessTest.java | 40 ++++++----- 25 files changed, 223 insertions(+), 216 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 515cf13a..21cf83b6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -46,7 +46,7 @@ String checkBuildStatuses() { var botClient = ChatBotServerClient.inProcessClient(SERVER_NAME); var organizations = botClient.listOrganizations(); for (var organization : organizations) { - var repos = botClient.listOrgRepos(organization.getId()); + var repos = botClient.listOrgRepos(organization.getOrganization()); repos.forEach(repo -> checkBuildStatus(botClient, repo, organization)); } return "success"; @@ -73,11 +73,11 @@ private static void throwProcessingError(Throwable throwable) { } private static CheckRepositoryBuild - checkRepoBuildCommand(RepositoryId id, Organization organization) { + checkRepoBuildCommand(RepositoryId repository, Organization organization) { return CheckRepositoryBuild .newBuilder() - .setId(id) - .setOrganization(organization.getId()) + .setRepository(repository) + .setOrganization(organization.getOrganization()) .setGoogleChatSpace(organization.getGoogleChatSpace()) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java index 3dc74e81..fd05cd0b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java @@ -111,7 +111,7 @@ public ImmutableList listRepositories() { .select(Organization.class) .run() .stream() - .map(Organization::getId) + .map(Organization::getOrganization) .collect(toImmutableList()); var orgRepos = client.asGuest() .select(OrganizationRepositories.class) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java index e7644bdf..0f109dc6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java @@ -41,7 +41,7 @@ final class OrgReposProjection */ @Subscribe void on(OrganizationRegistered e) { - builder().setId(e.getId()); + builder().setOrganization(e.getOrganization()); } /** @@ -50,7 +50,7 @@ void on(OrganizationRegistered e) { @Subscribe void on(RepositoryRegistered e) { var repositories = Sets.newHashSet(builder().getRepositoriesList()); - repositories.add(e.getId()); + repositories.add(e.getRepository()); builder().clearRepositories() .addAllRepositories(repositories); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 2c9bb3ba..501d647a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -47,7 +47,7 @@ OrganizationRegistered handle(RegisterOrganization c) { _info().log("Registering organization `%s`.", idAsString()); return OrganizationRegistered .newBuilder() - .setId(c.getId()) + .setOrganization(c.getOrganization()) .setGithubUrl(c.getGithubUrl()) .setName(c.getName()) .setTravisCiUrl(c.getTravisCiUrl()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 77ba987e..09db3f8e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -85,14 +85,14 @@ final class RepoBuildProcess @Assign EitherOf3 handle(CheckRepositoryBuild c) throws NoBuildsFound { - var repositoryId = c.getId(); + var repositoryId = c.getRepository(); _info().log("Checking build status for repository `%s`.", repositoryId.getValue()); var branchBuild = client.execute(BuildsQuery.forRepo(repositoryId.getValue())); if (isDefault(branchBuild.getLastBuild())) { _warn().log("No builds found for the repository `%s`.", repositoryId.getValue()); throw NoBuildsFound .newBuilder() - .setId(repositoryId) + .setRepository(repositoryId) .build(); } var buildState = buildStateFrom(branchBuild, c.getGoogleChatSpace()); @@ -109,33 +109,33 @@ EitherOf3 handle(CheckRepositoryBuild } private EitherOf3 - determineOutcome(RepositoryId id, BuildStateChange stateChange) { + determineOutcome(RepositoryId repository, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); var previousBuildState = stateChange.getPreviousValue(); var stateStatusChange = stateStatusChangeOf(newBuildState, previousBuildState); switch (stateStatusChange) { case FAILED: _info().log("Build for repository `%s` failed with status `%s`.", - id.getValue(), newBuildState.getState()); + repository.getValue(), newBuildState.getState()); var buildFailed = BuildFailed .newBuilder() - .setId(id) + .setRepository(repository) .setChange(stateChange) .vBuild(); return EitherOf3.withA(buildFailed); case RECOVERED: - _info().log("Build for repository `%s` is recovered.", id.getValue()); + _info().log("Build for repository `%s` is recovered.", repository.getValue()); var buildRecovered = BuildRecovered .newBuilder() - .setId(id) + .setRepository(repository) .setChange(stateChange) .vBuild(); return EitherOf3.withB(buildRecovered); case STABLE: - _info().log("Build for repository `%s` is stable.", id.getValue()); + _info().log("Build for repository `%s` is stable.", repository.getValue()); var buildStable = BuildStable .newBuilder() - .setId(id) + .setRepository(repository) .setChange(stateChange) .vBuild(); return EitherOf3.withC(buildStable); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java index d2cbd1c7..47d81703 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -43,10 +43,11 @@ final class RepositoryAggregate */ @Assign RepositoryRegistered handle(RegisterRepository c) { - _info().log("Registering repository `%s`.", idAsString()); + var repository = c.getRepository(); + _info().log("Registering repository `%s`.", repository.getValue()); var result = RepositoryRegistered .newBuilder() - .setId(c.getId()) + .setRepository(repository) .setName(c.getName()) .setGithubUrl(c.getGithubUrl()) .setTravisCiUrl(c.getTravisCiUrl()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java index cdea683d..7f069cf4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java @@ -30,5 +30,14 @@ public interface RepositoryAware { /** * Obtains the repository ID. */ - RepositoryId getId(); + default RepositoryId repository() { + return getRepository(); + } + + /** + * Obtains the repository ID. + * + * @implNote this is the Protobuf-level accessor. + */ + RepositoryId getRepository(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java index ea969667..82e7c32f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java @@ -35,13 +35,4 @@ @GeneratedMixin @Immutable public interface RepositoryAwareEvent extends RepositoryAware, EventMessage { - - /** - * Returns target repository ID as a singleton set. - * - * @apiNote This is a convenience method to be used within the event routing schemas. - */ - default Set repository() { - return withId(getId()); - } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 51049081..342ea4c5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -79,18 +79,18 @@ Iterable on(@External SpaceRegistered e) { _info().log("Spine organization is already initialized. Skipping the process."); return ImmutableSet.of(); } - var spaceId = e.getId(); - _info().log("Starting Spine organization initialization process in space `%s`.", - spaceId.getValue()); + var space = e.getSpace() + .getValue(); + _info().log("Starting Spine organization initialization process in space `%s`.", space); var commands = ImmutableSet.builder(); - commands.add(registerOrgCommand(SPINE_ORGANIZATION, spaceId.getValue())); + commands.add(registerOrgCommand(SPINE_ORGANIZATION, space)); travisClient.execute(ReposQuery.forOwner(SPINE_ORG)) .getRepositoriesList() .stream() .filter(repository -> WATCHED_REPOS.contains(repository.getName())) .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) .forEach(commands::add); - builder().setGoogleChatSpace(spaceId.getValue()) + builder().setGoogleChatSpace(space) .setInitialized(true); return commands.build(); } @@ -100,9 +100,9 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o _info().log("Registering `%s` repository.", slug); return RegisterRepository .newBuilder() + .setRepository(repository(slug)) .setOrganization(orgId) .setGithubUrl(githubUrlFor(slug)) - .setId(repository(slug)) .setName(repo.getName()) .setTravisCiUrl(travisUrlFor(slug)) .vBuild(); @@ -112,11 +112,11 @@ private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, Strin _info().log("Registering `%s` organization.", SPINE_ORG); return RegisterOrganization .newBuilder() + .setOrganization(spineOrgId) .setName("Spine Event Engine") .setWebsiteUrl(urlOfSpec("https://spine.io/")) .setTravisCiUrl(travisUrlFor(SPINE_ORG)) .setGithubUrl(githubUrlFor(SPINE_ORG)) - .setId(spineOrgId) .setGoogleChatSpace(spaceName) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index d6fe951a..876b0ee7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -88,7 +88,7 @@ private static BotRemovedFromSpace botRemovedFromSpace(ChatEvent chatEvent) { return BotRemovedFromSpace .newBuilder() .setEvent(chatEvent) - .setSpaceId(space(space.getName())) + .setSpace(space(space.getName())) .vBuild(); } @@ -97,7 +97,7 @@ private static BotAddedToSpace botAddedToSpace(ChatEvent chatEvent) { return BotAddedToSpace .newBuilder() .setEvent(chatEvent) - .setSpaceId(space(space.getName())) + .setSpace(space(space.getName())) .vBuild(); } @@ -106,7 +106,7 @@ private static MessageReceived messageReceived(ChatEvent chatEvent) { return MessageReceived .newBuilder() .setEvent(chatEvent) - .setMessageId(message(message.getName())) + .setMessage(message(message.getName())) .vBuild(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 267c0648..2ba9ae61 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -47,13 +47,13 @@ SpaceRegistered on(BotAddedToSpace e) { var space = e.getEvent() .getSpace(); var displayName = space.getDisplayName(); - var spaceId = e.getSpaceId(); + var spaceId = e.getSpace(); _info().log("Registering space `%s` (`%s`).", displayName, spaceId.getValue()); return SpaceRegistered .newBuilder() + .setSpace(spaceId) .setDisplayName(displayName) .setThreaded(isThreaded(space)) - .setId(spaceId) .vBuild(); } @@ -62,11 +62,11 @@ SpaceRegistered on(BotAddedToSpace e) { */ @Assign SpaceRegistered handle(RegisterSpace c) { - var spaceId = c.getId(); - _info().log("Registering space `%s`.", spaceId.getValue()); + var space = c.getSpace(); + _info().log("Registering space `%s`.", space.getValue()); var result = SpaceRegistered .newBuilder() - .setId(spaceId) + .setSpace(space) .setSingleUserBotDm(c.getSingleUserBotDm()) .setThreaded(c.getThreaded()) .setDisplayName(c.getDisplayName()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java index 5fba4ab4..53422983 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceRepository.java @@ -35,6 +35,6 @@ final class SpaceRepository extends AggregateRepository @Override protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); - routing.route(BotAddedToSpace.class, (event, context) -> withId(event.getSpaceId())); + routing.route(BotAddedToSpace.class, (event, context) -> withId(event.getSpace())); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index d5221c6f..059b73db 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -47,16 +47,16 @@ ThreadInitialized on(ThreadCreated e) { _info().log("A new thread `%s` created.", idAsString()); return ThreadInitialized .newBuilder() - .setId(e.getId()) .setThread(e.getThread()) - .setSpaceId(e.getSpaceId()) + .setResource(e.getResource()) + .setSpace(e.getSpace()) .vBuild(); } @Apply private void on(ThreadInitialized e) { - builder().setThread(e.getThread()) - .setSpaceId(e.getSpaceId()); + builder().setResource(e.getResource()) + .setSpace(e.getSpace()); } /** @@ -64,18 +64,19 @@ private void on(ThreadInitialized e) { */ @React MessageAdded on(MessageCreated e) { - var messageId = e.getId(); + var message = e.getMessage(); + var thread = e.getThread(); _info().log("A new message `%s` added to the thread `%s`.", - messageId.getValue(), idAsString()); + message.getValue(), thread.getValue()); return MessageAdded .newBuilder() - .setId(messageId) - .setThreadId(e.getThreadId()) + .setMessage(message) + .setThread(thread) .vBuild(); } @Apply private void on(MessageAdded e) { - builder().addMessages(e.getId()); + builder().addMessages(e.getMessage()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 79de14a8..701a10d7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -43,7 +43,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; -import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; /** * A process of notifying thread members about the changes in the watched resouces. @@ -61,10 +61,10 @@ final class ThreadChatProcess extends ProcessManager> on(@External BuildFailed e) { var change = e.getChange(); var buildState = change.getNewValue(); - var repositoryId = e.getId(); - _info().log("Build for repository `%s` failed.", repositoryId.getValue()); + var repository = e.getRepository(); + _info().log("Build for repository `%s` failed.", repository.getValue()); - return processBuildStateUpdate(buildState, repositoryId); + return processBuildStateUpdate(buildState, repository); } /** @@ -77,36 +77,36 @@ Pair> on(@External BuildFailed e) { Pair> on(@External BuildRecovered e) { var change = e.getChange(); var buildState = change.getNewValue(); - var repositoryId = e.getId(); - _info().log("Build for repository `%s` recovered.", repositoryId.getValue()); + var repository = e.getRepository(); + _info().log("Build for repository `%s` recovered.", repository.getValue()); - return processBuildStateUpdate(buildState, repositoryId); + return processBuildStateUpdate(buildState, repository); } private Pair> - processBuildStateUpdate(BuildState buildState, RepositoryId repositoryId) { - var sentMessage = client.sendBuildStateUpdate(buildState, state().getThread()); - var messageId = message(sentMessage.getName()); - var threadId = thread(repositoryId.getValue()); - var spaceId = space(buildState.getGoogleChatSpace()); + processBuildStateUpdate(BuildState buildState, RepositoryId repository) { + var sentMessage = client.sendBuildStateUpdate(buildState, state().getResource()); + var message = message(sentMessage.getName()); + var thread = thread(repository.getValue()); + var space = space(buildState.getGoogleChatSpace()); var messageCreated = MessageCreated .newBuilder() - .setId(messageId) - .setSpaceId(spaceId) - .setThreadId(threadId) + .setMessage(message) + .setSpace(space) + .setThread(thread) .vBuild(); if (shouldCreateThread()) { - var newThread = threadResourceOf(sentMessage.getThread() - .getName()); + var resource = threadResource(sentMessage.getThread() + .getName()); _debug().log("New thread `%s` created for repository `%s`.", - newThread.getName(), repositoryId.getValue()); - builder().setThread(newThread) - .setSpaceId(spaceId); + resource.getName(), repository.getValue()); + builder().setResource(resource) + .setSpace(space); var threadCreated = ThreadCreated .newBuilder() - .setId(threadId) - .setThread(newThread) - .setSpaceId(spaceId) + .setThread(thread) + .setResource(resource) + .setSpace(space) .vBuild(); return Pair.withNullable(messageCreated, threadCreated); } @@ -114,7 +114,7 @@ Pair> on(@External BuildRecovered e) { } private boolean shouldCreateThread() { - return Messages.isDefault(state().getThread()); + return Messages.isDefault(state().getResource()); } void setClient(GoogleChatClient client) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 062f4511..a3559e52 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -69,8 +69,8 @@ private static class RepositoryEventRoute @Override public Set apply(M event, EventContext context) { - var repositoryId = event.getId(); - return withId(thread(repositoryId.getValue())); + var repository = event.repository(); + return withId(thread(repository.getValue())); } } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java index 12696ed6..5defe992 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java @@ -36,7 +36,7 @@ final class ThreadRepository extends AggregateRepository routing) { super.setupEventRouting(routing); - routing.route(ThreadCreated.class, (event, context) -> withId(event.getId())); - routing.route(MessageCreated.class, (event, context) -> withId(event.getThreadId())); + routing.route(ThreadCreated.class, (event, context) -> withId(event.getThread())); + routing.route(MessageCreated.class, (event, context) -> withId(event.getThread())); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java index 4f604b64..0084a0cd 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -38,7 +38,7 @@ private ThreadResources() { /** * Creates a new {@link ThreadResource} with the specified {@code name}. */ - public static ThreadResource threadResourceOf(String name) { + public static ThreadResource threadResource(String name) { checkNotNull(name); return ThreadResource .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 292505ce..4502ff93 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -40,19 +40,20 @@ final class OrganizationAggregateTest extends GitHubContextAwareTest { @DisplayName("register an organization") final class Register { - private final OrganizationId organizationId = organization("TestOrganization"); + private static final String orgName = "Test Organization"; + private static final String googleChatSpace = "spaces/qwdp123ttQ"; + + private final OrganizationId organization = organization("TestOrganization"); private final Url githubUrl = urlOfSpec("https://github.com/TestOrganization"); private final Url travisCiUrl = urlOfSpec("https://travis-ci.com/TestOrganization"); private final Url websiteUrl = urlOfSpec("https://test-organization.com"); - private final String orgName = "Test Organization"; - private final String googleChatSpace = "spaces/qwdp123ttQ"; @BeforeEach void setUp() { var registerOrganization = RegisterOrganization .newBuilder() - .setId(organizationId) + .setOrganization(organization) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setWebsiteUrl(websiteUrl) @@ -67,7 +68,7 @@ void setUp() { void producingEvent() { var organizationRegistered = OrganizationRegistered .newBuilder() - .setId(organizationId) + .setOrganization(organization) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setWebsiteUrl(websiteUrl) @@ -82,14 +83,14 @@ void producingEvent() { void settingState() { var expectedState = Organization .newBuilder() - .setId(organizationId) + .setOrganization(organization) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setWebsiteUrl(websiteUrl) .setName(orgName) .setGoogleChatSpace(googleChatSpace) .vBuild(); - context().assertState(organizationId, Organization.class) + context().assertState(organization, Organization.class) .isEqualTo(expectedState); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 782d2898..fe15e197 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -46,26 +46,26 @@ @DisplayName("RepoBuildProcess should") final class RepoBuildProcessTest extends GitHubContextAwareTest { - private static final OrganizationId orgId = organization("SpineEventEngine"); - private static final RepositoryId repositoryId = repository("SpineEventEngine/web"); + private static final OrganizationId org = organization("SpineEventEngine"); + private static final RepositoryId repository = repository("SpineEventEngine/web"); private static final String chatSpace = "spaces/1245wrq"; @Test @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") void throwNoBuildsFoundRejection() { - travisClient().setBuildsFor(repositoryId.getValue(), + travisClient().setBuildsFor(repository.getValue(), RepoBranchBuildResponse.getDefaultInstance()); var checkRepoBuild = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) - .setOrganization(orgId) + .setRepository(repository) + .setOrganization(org) .setGoogleChatSpace(chatSpace) .vBuild(); context().receivesCommand(checkRepoBuild); var noBuildsFound = RepositoryBuildRejections.NoBuildsFound .newBuilder() - .setId(repositoryId) + .setRepository(repository) .vBuild(); context().assertEvent(noBuildsFound); } @@ -81,12 +81,12 @@ final class FailedBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), branchBuild); + travisClient().setBuildsFor(repository.getValue(), branchBuild); var checkRepoBuild = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGoogleChatSpace(chatSpace) - .setOrganization(orgId) + .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoBuild); } @@ -100,7 +100,7 @@ void producingEvent() { .vBuild(); var buildFailed = BuildFailed .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setChange(stateChange) .vBuild(); context().assertEvent(buildFailed); @@ -111,11 +111,11 @@ void producingEvent() { void settingState() { var expectedState = RepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setBuildState(buildState) .setRepositoryBuildState(buildState.getState()) .vBuild(); - context().assertState(repositoryId, RepositoryBuild.class) + context().assertState(repository, RepositoryBuild.class) .isEqualTo(expectedState); } } @@ -136,20 +136,20 @@ final class RecoveredBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), previousBranchBuild); + travisClient().setBuildsFor(repository.getValue(), previousBranchBuild); var checkRepoFailure = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGoogleChatSpace(chatSpace) - .setOrganization(orgId) + .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), newBranchBuild); + travisClient().setBuildsFor(repository.getValue(), newBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGoogleChatSpace(chatSpace) - .setOrganization(orgId) + .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); } @@ -164,7 +164,7 @@ void producingEvent() { .vBuild(); var buildFailed = BuildRecovered .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setChange(stateChange) .vBuild(); context().assertEvent(buildFailed); @@ -175,11 +175,11 @@ void producingEvent() { void settingState() { var expectedState = RepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setBuildState(newBuildState) .setRepositoryBuildState(newBuildState.getState()) .vBuild(); - context().assertState(repositoryId, RepositoryBuild.class) + context().assertState(repository, RepositoryBuild.class) .isEqualTo(expectedState); } } @@ -202,28 +202,28 @@ final class StableBuild { @BeforeEach void setUp() { - travisClient().setBuildsFor(repositoryId.getValue(), branchBuildOf(initialFailedBuild)); + travisClient().setBuildsFor(repository.getValue(), branchBuildOf(initialFailedBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGoogleChatSpace(chatSpace) - .setOrganization(orgId) + .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repositoryId.getValue(), previousBranchBuild); + travisClient().setBuildsFor(repository.getValue(), previousBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGoogleChatSpace(chatSpace) - .setOrganization(orgId) + .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); - travisClient().setBuildsFor(repositoryId.getValue(), newBranchBuild); + travisClient().setBuildsFor(repository.getValue(), newBranchBuild); var checkRepoStable = CheckRepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGoogleChatSpace(chatSpace) - .setOrganization(orgId) + .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoStable); } @@ -238,7 +238,7 @@ void producingEvent() { .vBuild(); var buildFailed = BuildStable .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setChange(stateChange) .vBuild(); context().assertEvent(buildFailed); @@ -249,11 +249,11 @@ void producingEvent() { void settingState() { var expectedState = RepositoryBuild .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setBuildState(newBuildState) .setRepositoryBuildState(newBuildState.getState()) .vBuild(); - context().assertState(repositoryId, RepositoryBuild.class) + context().assertState(repository, RepositoryBuild.class) .isEqualTo(expectedState); } } @@ -264,7 +264,7 @@ private static RepoBranchBuildResponse branchBuildOf(Build build) { .setLastBuild(build) .setName("master") .setRepository(Repository.newBuilder() - .setSlug(repositoryId.getValue())) + .setSlug(repository.getValue())) .buildPartial(); } @@ -361,7 +361,7 @@ private static Repository webRepository() { .newBuilder() .setId(1112) .setName("web") - .setSlug(repositoryId.getValue()) + .setSlug(repository.getValue()) .buildPartial(); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 552c603b..8df31fbd 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -33,7 +33,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.net.Urls.urlOfSpec; +import static io.spine.net.Urls.githubUrlFor; +import static io.spine.net.Urls.travisUrlFor; @DisplayName("RepositoryAggregate should") final class RepositoryAggregateTest extends GitHubContextAwareTest { @@ -42,23 +43,25 @@ final class RepositoryAggregateTest extends GitHubContextAwareTest { @DisplayName("register a repository") final class Register { - private final RepositoryId repositoryId = repository("SpineEventEngine/base"); - private final OrganizationId organizationId = organization("SpineEventEngine"); + private static final String ORG_SLUG = "SpineEventEngine"; + private static final String REPO_SLUG = ORG_SLUG + "/base"; + private static final String REPO_NAME = "Spine Base"; - private final Url githubUrl = urlOfSpec("https://github.com/SpineEventEngine/base"); - private final Url travisCiUrl = - urlOfSpec("https://travis-ci.com/github/SpineEventEngine/base"); - private final String repositoryName = "Spine Base"; + private final RepositoryId repository = repository(REPO_SLUG); + private final OrganizationId organization = organization(ORG_SLUG); + + private final Url githubUrl = githubUrlFor(REPO_SLUG); + private final Url travisCiUrl = travisUrlFor(REPO_SLUG); @BeforeEach void setUp() { var registerRepository = RegisterRepository .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) - .setName(repositoryName) - .setOrganization(organizationId) + .setName(REPO_NAME) + .setOrganization(organization) .vBuild(); context().receivesCommand(registerRepository); } @@ -68,11 +71,11 @@ void setUp() { void producingEvent() { var repositoryRegistered = RepositoryRegistered .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) - .setName(repositoryName) - .setOrganization(organizationId) + .setName(REPO_NAME) + .setOrganization(organization) .vBuild(); context().assertEvent(repositoryRegistered); } @@ -82,13 +85,13 @@ void producingEvent() { void settingState() { var expectedState = Repository .newBuilder() - .setId(repositoryId) + .setRepository(repository) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) - .setName(repositoryName) - .setOrganization(organizationId) + .setName(REPO_NAME) + .setOrganization(organization) .vBuild(); - context().assertState(repositoryId, Repository.class) + context().assertState(repository, Repository.class) .isEqualTo(expectedState); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 6f00cde6..1deb883c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -57,7 +57,7 @@ void setUp() { travisClient().setRepositoriesFor(SPINE_ORGANIZATION.getValue(), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() - .setId(spaceId) + .setSpace(spaceId) .setDisplayName("Test space") .setThreaded(true) .vBuild(); @@ -71,7 +71,7 @@ void settingState() { .newBuilder() .setGoogleChatSpace(spaceId.getValue()) .setInitialized(true) - .setId(SPINE_ORGANIZATION) + .setOrganization(SPINE_ORGANIZATION) .vBuild(); context().assertState(SPINE_ORGANIZATION, OrganizationInit.class) .isEqualTo(expectedState); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index 8cb34ad4..717ba9b7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -50,7 +50,7 @@ void addBot() { var botAddedToSpace = BotAddedToSpace .newBuilder() .setEvent(chatEvent) - .setSpaceId(spaceId) + .setSpace(spaceId) .vBuild(); // when context().receivesExternalEvent(chatEvent); @@ -66,7 +66,7 @@ void removeBot() { var botRemovedFromSpace = BotRemovedFromSpace .newBuilder() .setEvent(chatEvent) - .setSpaceId(spaceId) + .setSpace(spaceId) .vBuild(); // when context().receivesExternalEvent(chatEvent); @@ -82,7 +82,7 @@ void receiveIncomingMessage() { var messageReceived = MessageReceived .newBuilder() .setEvent(chatEvent) - .setMessageId(messageId) + .setMessage(messageId) .vBuild(); // when context().receivesExternalEvent(chatEvent); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 42aa240f..3b02b5b0 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -39,8 +39,8 @@ @DisplayName("SpaceAggregate should") final class SpaceAggregateTest extends GoogleChatContextAwareTest { - private static final SpaceId spaceId = space("spaces/poqwdpQ21"); - private static final String displayName = "Spine Developers"; + private static final SpaceId SPACE = space("spaces/poqwdpQ21"); + private static final String DISPLAY_NAME = "Spine Developers"; @Nested @DisplayName("register a space") @@ -50,9 +50,9 @@ final class Register { void setUp() { var registerSpace = RegisterSpace .newBuilder() - .setId(spaceId) + .setSpace(SPACE) .setThreaded(true) - .setDisplayName(displayName) + .setDisplayName(DISPLAY_NAME) .vBuild(); context().receivesCommand(registerSpace); } @@ -62,8 +62,8 @@ void setUp() { void producingEvent() { var spaceRegistered = SpaceRegistered .newBuilder() - .setId(spaceId) - .setDisplayName(displayName) + .setSpace(SPACE) + .setDisplayName(DISPLAY_NAME) .setThreaded(true) .vBuild(); context().assertEvent(spaceRegistered); @@ -74,11 +74,11 @@ void producingEvent() { void settingState() { var expectedState = Space .newBuilder() - .setId(spaceId) + .setSpace(SPACE) .setThreaded(true) - .setDisplayName(displayName) + .setDisplayName(DISPLAY_NAME) .vBuild(); - context().assertState(spaceId, Space.class) + context().assertState(SPACE, Space.class) .isEqualTo(expectedState); } } @@ -99,7 +99,7 @@ void setUp() { .vBuild(); var botAddedToSpace = BotAddedToSpace .newBuilder() - .setSpaceId(spaceId) + .setSpace(SPACE) .setEvent(chatEvent) .vBuild(); context().receivesEvent(botAddedToSpace); @@ -110,8 +110,8 @@ void setUp() { void producingEvent() { var spaceRegistered = SpaceRegistered .newBuilder() - .setId(spaceId) - .setDisplayName(displayName) + .setSpace(SPACE) + .setDisplayName(DISPLAY_NAME) .setThreaded(true) .vBuild(); context().assertEvent(spaceRegistered); @@ -122,19 +122,19 @@ void producingEvent() { void settingState() { var expectedState = Space .newBuilder() - .setId(spaceId) + .setSpace(SPACE) .setThreaded(true) - .setDisplayName(displayName) + .setDisplayName(DISPLAY_NAME) .vBuild(); - context().assertState(spaceId, Space.class) + context().assertState(SPACE, Space.class) .isEqualTo(expectedState); } private io.spine.chatbot.google.chat.incoming.Space chatSpace() { return io.spine.chatbot.google.chat.incoming.Space .newBuilder() - .setName(spaceId.getValue()) - .setDisplayName(displayName) + .setName(SPACE.getValue()) + .setDisplayName(DISPLAY_NAME) .setType(SpaceType.ROOM) .vBuild(); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index fc9d2937..ff83e08d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -37,7 +37,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; -import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @DisplayName("ThreadAggregate should") final class ThreadAggregateTest extends GoogleChatContextAwareTest { @@ -46,18 +46,18 @@ final class ThreadAggregateTest extends GoogleChatContextAwareTest { @DisplayName("initialize a thread") final class InitThread { - private final ThreadId threadId = thread("SpineEventEngine/base"); - private final SpaceId spaceId = space("spaces/qpojdwpiq1241"); - private final ThreadResource threadResource = - threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); + private final ThreadId thread = thread("SpineEventEngine/base"); + private final SpaceId space = space("spaces/qpojdwpiq1241"); + private final ThreadResource resource = + threadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); @BeforeEach void setUp() { var threadCreated = ThreadCreated .newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResource) + .setThread(thread) + .setSpace(space) + .setResource(resource) .vBuild(); context().receivesEvent(threadCreated); } @@ -67,9 +67,9 @@ void setUp() { void producingEvent() { var threadInitialized = ThreadInitialized .newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResource) + .setThread(thread) + .setSpace(space) + .setResource(resource) .vBuild(); context().assertEvent(threadInitialized); } @@ -79,11 +79,11 @@ void producingEvent() { void settingState() { var state = Thread .newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResource) + .setThread(thread) + .setSpace(space) + .setResource(resource) .vBuild(); - context().assertState(threadId, Thread.class) + context().assertState(thread, Thread.class) .isEqualTo(state); } } @@ -92,26 +92,25 @@ void settingState() { @DisplayName("add created message") final class AddMessage { - private final ThreadId threadId = thread("SpineEventEngine/base"); - private final SpaceId spaceId = space("spaces/qpojdwpiq1241"); - private final MessageId messageId = - message("spaces/qpojdwpiq1241/messages/dqpwjpop12"); + private final ThreadId thread = thread("SpineEventEngine/base"); + private final SpaceId space = space("spaces/qpojdwpiq1241"); + private final MessageId message = message("spaces/qpojdwpiq1241/messages/dqpwjpop12"); private final ThreadResource threadResource = - threadResourceOf("spaces/qpojdwpiq1241/threads/qwdojp12"); + threadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); @BeforeEach void setUp() { var threadCreated = ThreadCreated .newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResource) + .setThread(thread) + .setSpace(space) + .setResource(threadResource) .vBuild(); var messageCreated = MessageCreated .newBuilder() - .setId(messageId) - .setSpaceId(spaceId) - .setThreadId(threadId) + .setMessage(message) + .setSpace(space) + .setThread(thread) .vBuild(); context().receivesEvent(threadCreated) .receivesEvent(messageCreated); @@ -122,8 +121,8 @@ void setUp() { void producingEvent() { var messageAdded = MessageAdded .newBuilder() - .setId(messageId) - .setThreadId(threadId) + .setMessage(message) + .setThread(thread) .vBuild(); context().assertEvent(messageAdded); } @@ -133,12 +132,12 @@ void producingEvent() { void settingState() { var state = Thread .newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResource) - .addMessages(messageId) + .setThread(thread) + .setSpace(space) + .setResource(threadResource) + .addMessages(message) .vBuild(); - context().assertState(threadId, Thread.class) + context().assertState(thread, Thread.class) .isEqualTo(state); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 0c1e0034..8eb077e5 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -42,7 +42,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; -import static io.spine.chatbot.server.google.chat.ThreadResources.threadResourceOf; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @DisplayName("ThreadChatProcess should") final class ThreadChatProcessTest { @@ -57,7 +57,7 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, BuildStateChange stateChange) { return BuildFailed .newBuilder() - .setId(repositoryId) + .setRepository(repositoryId) .setChange(stateChange) .vBuild(); } @@ -73,7 +73,7 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, BuildStateChange stateChange) { return BuildRecovered .newBuilder() - .setId(repositoryId) + .setRepository(repositoryId) .setChange(stateChange) .vBuild(); } @@ -81,11 +81,13 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, private abstract static class BuildStateChanged extends GoogleChatContextAwareTest { - private final RepositoryId repositoryId = repository("SpineEventEngine/money"); - private final ThreadId threadId = thread(repositoryId.getValue()); - private final String googleChatSpace = "spaces/1241pjwqe"; - private final SpaceId spaceId = space(googleChatSpace); - private final String buildNumber = "551"; + private static final String googleChatSpace = "spaces/1241pjwqe"; + private static final String buildNumber = "551"; + + private final RepositoryId repository = repository("SpineEventEngine/money"); + private final ThreadId thread = thread(repository.getValue()); + private final SpaceId space = space(googleChatSpace); + private final Thread newThread = new Thread().setName("spaces/1241pjwqe/threads/k12d1o2r1"); private final Message sentMessage = new Message() .setName("spaces/1241pjwqe/messages/12154363643624") @@ -103,7 +105,7 @@ void setUp() { .newBuilder() .setNewValue(newBuildState) .vBuild(); - var buildFailed = buildStateChangeEvent(repositoryId, buildStateChange); + var buildFailed = buildStateChangeEvent(repository, buildStateChange); context().receivesExternalEvent(buildFailed); } @@ -115,15 +117,15 @@ abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, void producingEvents() { var messageCreated = MessageCreated .newBuilder() - .setId(message(sentMessage.getName())) - .setThreadId(threadId) - .setSpaceId(spaceId) + .setMessage(message(sentMessage.getName())) + .setThread(thread) + .setSpace(space) .vBuild(); var threadCreated = ThreadCreated .newBuilder() - .setId(threadId) - .setThread(threadResourceOf(newThread.getName())) - .setSpaceId(spaceId) + .setThread(thread) + .setResource(threadResource(newThread.getName())) + .setSpace(space) .vBuild(); context().assertEvent(messageCreated); context().assertEvent(threadCreated); @@ -134,11 +136,11 @@ void producingEvents() { void settingState() { var expectedState = ThreadChat .newBuilder() - .setId(threadId) - .setSpaceId(spaceId) - .setThread(threadResourceOf(newThread.getName())) + .setThread(thread) + .setSpace(space) + .setResource(threadResource(newThread.getName())) .vBuild(); - context().assertState(threadId, ThreadChat.class) + context().assertState(thread, ThreadChat.class) .isEqualTo(expectedState); } } From 24d7a949ede29f2c02e95d925d9cb064f86855d5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 15:34:03 +0300 Subject: [PATCH 270/492] Initial env definition --- ENVIRONMENT.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 ENVIRONMENT.md diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md new file mode 100644 index 00000000..ac31fa38 --- /dev/null +++ b/ENVIRONMENT.md @@ -0,0 +1,73 @@ +Cloud Environment setup +------------ + +The ChatBot application is working in the cloud environment on the Google Cloud Platform (GCP) and +this document provides an overview of the currently configured environment. + + +## Hangouts Chat API + +The bot uses [Hangout Chat API][chat-api] and is linked to the GCP project. Currently, it's only +possible to have a single bot per the GCP project. + +The bot configuration could be done only via the web UI console as of the writing. It is published +in accordance to the publishing [guide][publishing-guide] where the essential configurations are: + +1. `Functionality` — check `Bot works in rooms`. We do not expect the bot to work in direct messages. +2. `Connection settings` — choose `Cloud Pub/Sub` and enter a Pub/Sub topic name that'd be used + to deliver messages from users to the bot. (for the Pub/Sub details see + [Pub/Sub](#pubsub) section) +3. `Permissions` — choose `Specific people and groups in your domain` and list individuals or +groups in the domain who'd be able to install the bot. + +[chat-api]: https://developers.google.com/hangouts/chat +[publishing-guide]: https://developers.google.com/hangouts/chat/how-tos/bots-publish + +## Pub/Sub + +The application is built with resilience in mind and even though it exposes some REST APIs, +it is not intended to handle to load directly. Instead, we rely on the Google [Pub/Sub][pubsub] +async messaging service to receive the incoming messages and then stream the into the app. + +At the moment of writing, the app requires the following Pub/Sub topics to be configured: + +1. `incoming-bot-messages` — that is the topic that is used in the `Connection settings` of the + bot configuration. The Hangouts Chat system takes care of propagating users messages to this + topic. + + For the topic we configure the `incoming-bot-messages-cloud-run` push subscription that + delivers messages to the `/chat/incoming/event` endpoint. The subscription is configured + with a backoff retry policy and the acknowledgement deadline of 600 seconds. + + Also, the `dead lettering` is configured for the subscription, so all the undelivered + messages are sent to our next topic — `dead-incoming-bot-messages`. + + The subscription uses `cloud-run-pubsub-invoker` service account to implement service2service + authentication (see [IAM](#iam) section for details). + +2. `dead-incoming-bot-messages` — the topic that holds possible undelivered incoming messages. + + For the topic we configure the `dead-incoming-bot-messages` pull never-expired subscription. + In case of an undelivered message, one could go and pull it from the subscription. + +3. `repository-checks` — the topic that delivers scheduled tasks to check the watched resources + build state (see [Cloud Scheduler](#cloud-scheduler) section for details) + + For the topic we configure the `repository-checks-cloud-run` subscription that delivers messages + to the `/repositories/builds/check`. The subscription uses the same `cloud-run-pubsub-invoker` + service account as the `incoming-bot-messages-cloud-run` (see [IAM](#iam) section for details). + +[pubsub]: https://cloud.google.com/pubsub + +## Cloud Scheduler + +For the CRON-based needs we rely on the [Cloud Scheduler][scheduler] service. + +The scheduler service allows to configure multiple scheduled tasks that can deliver the task +payload to a particular target (HTTP endpoint, Pub/Sub topic or AppEngine endpoint). + +For our needs, we configure a single CRON task `repositories-check-trigger` that emits +a Pub/Sub message with an empty payload to the `repository-checks` topic. We configure the task +to run every hour using the following unix-cron format expression: `0 * * * *`. + +[scheduler]: https://cloud.google.com/scheduler From 4f6f1fceb24b1613b0cd85cd5c8f5125f578ee7b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 23 Jun 2020 15:34:10 +0300 Subject: [PATCH 271/492] Add TODOs --- ENVIRONMENT.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index ac31fa38..b2bfbb55 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -71,3 +71,14 @@ a Pub/Sub message with an empty payload to the `repository-checks` topic. We con to run every hour using the following unix-cron format expression: `0 * * * *`. [scheduler]: https://cloud.google.com/scheduler + +## Cloud Run + +We use Cloud Run as our main compute platform for the ChatBot application. Cloud Run is a managed +serverless solution that works with Docker. + +//TODO:2020-06-23:ysergiichuk: describe Cloud run usage. + +//TODO:2020-06-23:ysergiichuk: add IAM section. + +//TODO:2020-06-23:ysergiichuk: add Cloud Build section. From 12504bc4fcfde7dc779757e98c6e97fcc3e47267 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 11:38:11 +0300 Subject: [PATCH 272/492] Encapsulate fields --- .../spine/chatbot/PubsubPushNotificationDeserializerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java index 0e1265a9..24ce0596 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java @@ -36,10 +36,10 @@ @MicronautTest @DisplayName("PubsubPushNotificationDeserializer should") -class PubsubPushNotificationDeserializerTest { +final class PubsubPushNotificationDeserializerTest { @Inject - ObjectMapperFactory mapperFactory; + private ObjectMapperFactory mapperFactory; @Test @DisplayName("deserialize Pubsub message") From 317aa4dde043f19dd15ba8e838e89f9341113079 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 14:30:43 +0300 Subject: [PATCH 273/492] Add note about conforming to the 3rd party API --- .../google/chat/incoming/incoming_chat_messages.proto | 8 ++++++++ .../src/main/proto/spine/chatbot/travis/travis.proto | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 5b762096..7884a30d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -20,6 +20,14 @@ syntax = "proto3"; +// This file contains the proto definitions that conforms to the +// +// event formats of the Hangouts Chat. +// +// We use the defined protos instead of hand-crafting the dedicated classes and managing +// the JSON conversion manually. +// + package spine.chatbot.google.chat.incoming; import "spine/options.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index c3236825..0fc1a6d3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -20,6 +20,13 @@ syntax = "proto3"; +// This file contains the proto definitions that conforms to the +// Travis CI API v3 data types. +// +// We use the defined protos instead of hand-crafting the dedicated classes and managing +// the JSON conversion manually. +// + package spine.chatbot.travis; import "spine/options.proto"; From 8d3a1715c828052c97ff62df9dd15f4fdd0b81c4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 17:23:51 +0300 Subject: [PATCH 274/492] Update shadow plugin version --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a1a72423..c44aa090 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -31,7 +31,7 @@ repositories { dependencies { implementation("net.ltgt.gradle:gradle-errorprone-plugin:1.2.1") implementation("net.ltgt.gradle:gradle-apt-plugin:0.21") - implementation("com.github.jengelman.gradle.plugins:shadow:5.2.0") + implementation("com.github.jengelman.gradle.plugins:shadow:6.0.0") implementation("gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.4.0") implementation("io.spine.tools:spine-bootstrap:1.5.23") implementation("net.saliman:gradle-properties-plugin:1.5.1") From 7c4dcb290a4cb49ee15f711bb171140498fce242 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 17:28:17 +0300 Subject: [PATCH 275/492] Bump dependencies --- buildSrc/src/main/kotlin/deps.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index 913306c5..3e555f2b 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -22,17 +22,17 @@ object Versions { const val checkerFramework = "3.4.1" const val errorProne = "2.4.0" const val pmd = "6.24.0" - const val checkstyle = "8.29" + const val checkstyle = "8.33" const val findBugs = "3.0.2" const val guava = "29.0-jre" const val flogger = "0.5.1" const val junit5 = "5.6.2" const val truth = "1.0.1" - const val micronaut = "2.0.0.RC1" + const val micronaut = "2.0.0.RC2" const val spineGcloud = "1.5.0" - const val googleSecretManager = "1.0.1" + const val googleSecretManager = "1.1.0" const val googlePubsubProto = "1.89.0" - const val googleChat = "v1-rev20200502-1.30.9" + const val googleChat = "v1-rev20200617-1.30.9" const val googleAuth = "0.20.0" const val log4j2 = "2.13.3" } From 1355b47117bce27ce4ca6b27df4fbb18c0ce56be Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 17:40:01 +0300 Subject: [PATCH 276/492] Update Spine gcloud version and add spine-pubsub --- buildSrc/src/main/kotlin/deps.kt | 10 +++++++--- google-chat-bot/build.gradle.kts | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index 3e555f2b..dd45ef72 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -29,9 +29,8 @@ object Versions { const val junit5 = "5.6.2" const val truth = "1.0.1" const val micronaut = "2.0.0.RC2" - const val spineGcloud = "1.5.0" + const val spineGcloud = "1.5.22" const val googleSecretManager = "1.1.0" - const val googlePubsubProto = "1.89.0" const val googleChat = "v1-rev20200617-1.30.9" const val googleAuth = "0.20.0" const val log4j2 = "2.13.3" @@ -57,6 +56,12 @@ object Build { val micronaut = Micronaut val google = Google val log4j2 = Log4j2 + var spine = Spine +} + +object Spine { + const val datastore = "io.spine.gcloud:spine-datastore:${Versions.spineGcloud}" + const val pubsub = "io.spine.gcloud:spine-pubsub:${Versions.spineGcloud}" } object Log4j2 { @@ -67,7 +72,6 @@ object Log4j2 { object Google { const val secretManager = "com.google.cloud:google-cloud-secretmanager:${Versions.googleSecretManager}" - const val pubsubProto = "com.google.api.grpc:proto-google-cloud-pubsub-v1:${Versions.googlePubsubProto}" const val chat = "com.google.apis:google-api-services-chat:${Versions.googleChat}" const val auth = "com.google.auth:google-auth-library-oauth2-http:${Versions.googleAuth}" } diff --git a/google-chat-bot/build.gradle.kts b/google-chat-bot/build.gradle.kts index 920eb774..a79d9134 100644 --- a/google-chat-bot/build.gradle.kts +++ b/google-chat-bot/build.gradle.kts @@ -55,9 +55,10 @@ dependencies { exclude("org.apache.logging.log4j:log4j-core") } - implementation("io.spine.gcloud:spine-datastore:${Deps.versions.spineGcloud}") + implementation(Deps.build.spine.datastore) + implementation(Deps.build.spine.pubsub) + implementation(Deps.build.google.secretManager) - implementation(Deps.build.google.pubsubProto) implementation(Deps.build.google.chat) implementation(Deps.build.google.auth) From 51c2e546873893efe6a6c4e13dad3fba20f3e410 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 17:49:46 +0300 Subject: [PATCH 277/492] Migrate to `spine-pubsub`. --- .../java/io/spine/chatbot/BeanFactory.java | 14 +++++------ .../chatbot/IncomingEventsController.java | 4 ++-- .../proto/google/pubsub/v1/pubsub_push.proto | 24 ------------------- .../chatbot/IncomingEventsControllerTest.java | 4 ++-- ...ubsubPushNotificationDeserializerTest.java | 6 ++--- 5 files changed, 14 insertions(+), 38 deletions(-) delete mode 100644 google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 3dd87e1c..594ba7ae 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -26,10 +26,10 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.annotations.VisibleForTesting; import com.google.pubsub.v1.PubsubMessage; -import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.context.annotation.Bean; import io.micronaut.context.annotation.Factory; import io.spine.json.Json; +import io.spine.pubsub.PubsubPushRequest; import javax.inject.Singleton; import java.io.IOException; @@ -41,7 +41,7 @@ final class BeanFactory { /** - * Registers {@link PubsubPushNotification push notification} Jackson deserializer. + * Registers {@link PubsubPushRequest push request} Jackson deserializer. */ @Singleton @Bean @@ -50,17 +50,17 @@ PubsubPushNotificationDeserializer pubsubDeserializer() { } /** - * Spine-based {@link PubsubPushNotification} Jackson deserializer. + * Spine-based {@link PubsubPushRequest} Jackson deserializer. * * @see * Jackson Deserialization */ @VisibleForTesting static final class PubsubPushNotificationDeserializer - extends JsonDeserializer { + extends JsonDeserializer { /** - * Deserializes {@link PubsubPushNotification} JSON string into a Protobuf message. + * Deserializes {@link PubsubPushRequest} JSON string into a Protobuf message. * *

While Protobuf JSON parser is not able to handle same fields that are set using * {@code lowerCamelCase} and {@code snake_case} notations, we manually drop duplicate @@ -71,7 +71,7 @@ static final class PubsubPushNotificationDeserializer * fields */ @Override - public PubsubPushNotification deserialize(JsonParser parser, DeserializationContext ctxt) { + public PubsubPushRequest deserialize(JsonParser parser, DeserializationContext ctxt) { try { var jsonNode = ctxt.readTree(parser); var messageNode = (ObjectNode) jsonNode.get("message"); @@ -80,7 +80,7 @@ public PubsubPushNotification deserialize(JsonParser parser, DeserializationCont var pubsubMessage = Json.fromJson(messageNode.toString(), PubsubMessage.class); var subscription = jsonNode.get("subscription") .asText(); - var result = PubsubPushNotification + var result = PubsubPushRequest .newBuilder() .setMessage(pubsubMessage) .setSubscription(subscription) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index d60f0841..7abcbe81 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -20,7 +20,6 @@ package io.spine.chatbot; -import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; @@ -29,6 +28,7 @@ import io.spine.core.UserId; import io.spine.json.Json; import io.spine.logging.Logging; +import io.spine.pubsub.PubsubPushRequest; import io.spine.server.integration.ThirdPartyContext; import static io.micronaut.http.MediaType.APPLICATION_JSON; @@ -48,7 +48,7 @@ final class IncomingEventsController implements Logging { *

Dispatches the event using {@link ThirdPartyContext}. */ @Post(value = "/incoming/event", consumes = APPLICATION_JSON) - String on(@Body PubsubPushNotification pushNotification) { + String on(@Body PubsubPushRequest pushNotification) { var message = pushNotification.getMessage(); var chatEventJson = message.getData() .toStringUtf8(); diff --git a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto b/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto deleted file mode 100644 index 2205e71d..00000000 --- a/google-chat-bot/src/main/proto/google/pubsub/v1/pubsub_push.proto +++ /dev/null @@ -1,24 +0,0 @@ -syntax = "proto3"; - -package google.pubsub.v1; - -import "spine/options.proto"; - -option java_outer_classname = "PubsubPushProto"; -option java_package = "com.google.pubsub.v1"; -option java_multiple_files = true; -option java_generate_equals_and_hash = true; - -import "google/pubsub/v1/pubsub.proto"; - -// Pubsub push message notification. -message PubsubPushNotification { - - // Pubsub message. - PubsubMessage message = 1 [(required) = true]; - - // The name of the Pubsub subscription that pushed the current notification. - // Format is `projects/{project}/subscriptions/{subscription}`. - // - string subscription = 2 [(required) = true, (pattern).regex = "projects/.+/subscriptions/.+"]; -} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 4247da1a..07d6e21e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -22,7 +22,6 @@ import com.google.protobuf.ByteString; import com.google.pubsub.v1.PubsubMessage; -import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.http.MediaType; import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; @@ -32,6 +31,7 @@ import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.json.Json; +import io.spine.pubsub.PubsubPushRequest; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -73,7 +73,7 @@ void receiveAndDecode() { .setMessageId("129y418y4houfhiuehwr") .setData(ByteString.copyFromUtf8(CHAT_MESSAGE_EVENT)) .build(); - var pushNotification = PubsubPushNotification + var pushNotification = PubsubPushRequest .newBuilder() .setMessage(pubsubMessage) .setSubscription("projects/test-project/subscriptions/test-subscription") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java index 24ce0596..d636e034 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java @@ -25,9 +25,9 @@ import com.google.protobuf.ByteString; import com.google.protobuf.util.Timestamps; import com.google.pubsub.v1.PubsubMessage; -import com.google.pubsub.v1.PubsubPushNotification; import io.micronaut.jackson.ObjectMapperFactory; import io.micronaut.test.annotation.MicronautTest; +import io.spine.pubsub.PubsubPushRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -51,7 +51,7 @@ void deserializePubsubMessage() throws JsonProcessingException, ParseException { .setPublishTime(Timestamps.parse("2020-06-21T20:48:25.908Z")) .setData(ByteString.copyFromUtf8("{\"key\":\"value\"}")) .buildPartial(); - var expectedResult = PubsubPushNotification + var expectedResult = PubsubPushRequest .newBuilder() .setSubscription("projects/test-project/subscriptions/test-subscription") .setMessage(pubsubMessage) @@ -60,7 +60,7 @@ void deserializePubsubMessage() throws JsonProcessingException, ParseException { var mapper = mapperFactory.objectMapper(null, null); var pushNotification = mapper.readValue(PUSH_NOTIFICATION_JSON, - PubsubPushNotification.class); + PubsubPushRequest.class); ProtoTruth.assertThat(pushNotification) .isEqualTo(expectedResult); } From c2016202c865a5694d476d82e7b74711aa956fb2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 18:32:05 +0300 Subject: [PATCH 278/492] Use `id` field in aggregate IDs and commands that create these aggregates. --- .../main/java/io/spine/chatbot/RepositoriesController.java | 4 ++-- .../java/io/spine/chatbot/client/ChatBotServerClient.java | 2 +- .../spine/chatbot/server/github/OrganizationAggregate.java | 2 +- .../io/spine/chatbot/server/github/SpineOrgInitProcess.java | 2 +- .../io/spine/chatbot/server/google/chat/SpaceAggregate.java | 2 +- .../src/main/proto/spine/chatbot/github/organization.proto | 2 +- .../proto/spine/chatbot/github/organization_commands.proto | 2 +- .../main/proto/spine/chatbot/github/organization_init.proto | 2 +- .../spine/chatbot/github/organization_init_commands.proto | 2 +- .../spine/chatbot/github/organization_repositories.proto | 2 +- .../src/main/proto/spine/chatbot/github/repository.proto | 4 ++-- .../spine/chatbot/github/repository_build_commands.proto | 4 ++-- .../src/main/proto/spine/chatbot/google/chat/space.proto | 2 +- .../proto/spine/chatbot/google/chat/space_commands.proto | 2 +- .../src/main/proto/spine/chatbot/google/chat/thread.proto | 6 +++--- .../main/proto/spine/chatbot/google/chat/thread_chat.proto | 2 +- .../proto/spine/chatbot/google/chat/thread_events.proto | 4 ++-- .../chatbot/server/github/OrganizationAggregateTest.java | 4 ++-- .../chatbot/server/github/RepositoryAggregateTest.java | 2 +- .../chatbot/server/google/chat/SpaceAggregateTest.java | 6 +++--- .../chatbot/server/google/chat/ThreadAggregateTest.java | 4 ++-- 21 files changed, 31 insertions(+), 31 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 21cf83b6..0d2f944d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -46,7 +46,7 @@ String checkBuildStatuses() { var botClient = ChatBotServerClient.inProcessClient(SERVER_NAME); var organizations = botClient.listOrganizations(); for (var organization : organizations) { - var repos = botClient.listOrgRepos(organization.getOrganization()); + var repos = botClient.listOrgRepos(organization.getId()); repos.forEach(repo -> checkBuildStatus(botClient, repo, organization)); } return "success"; @@ -77,7 +77,7 @@ private static void throwProcessingError(Throwable throwable) { return CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setOrganization(organization.getOrganization()) + .setOrganization(organization.getId()) .setGoogleChatSpace(organization.getGoogleChatSpace()) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java index fd05cd0b..3dc74e81 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java @@ -111,7 +111,7 @@ public ImmutableList listRepositories() { .select(Organization.class) .run() .stream() - .map(Organization::getOrganization) + .map(Organization::getId) .collect(toImmutableList()); var orgRepos = client.asGuest() .select(OrganizationRepositories.class) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 501d647a..9931db20 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -47,7 +47,7 @@ OrganizationRegistered handle(RegisterOrganization c) { _info().log("Registering organization `%s`.", idAsString()); return OrganizationRegistered .newBuilder() - .setOrganization(c.getOrganization()) + .setOrganization(c.getId()) .setGithubUrl(c.getGithubUrl()) .setName(c.getName()) .setTravisCiUrl(c.getTravisCiUrl()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 342ea4c5..175c1aac 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -112,7 +112,7 @@ private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, Strin _info().log("Registering `%s` organization.", SPINE_ORG); return RegisterOrganization .newBuilder() - .setOrganization(spineOrgId) + .setId(spineOrgId) .setName("Spine Event Engine") .setWebsiteUrl(urlOfSpec("https://spine.io/")) .setTravisCiUrl(travisUrlFor(SPINE_ORG)) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 2ba9ae61..e6afa1a4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -62,7 +62,7 @@ SpaceRegistered on(BotAddedToSpace e) { */ @Assign SpaceRegistered handle(RegisterSpace c) { - var space = c.getSpace(); + var space = c.getId(); _info().log("Registering space `%s`.", space.getValue()); var result = SpaceRegistered .newBuilder() diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index ee88896b..c847ece0 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -39,7 +39,7 @@ message Organization { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - OrganizationId organization = 1; + OrganizationId id = 1; // Name of the GitHub organization. string name = 2; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index e67f4bfc..28266364 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -37,7 +37,7 @@ import "spine/chatbot/github/identifiers.proto"; // An organization registration command. message RegisterOrganization { - OrganizationId organization = 1 [(required) = true]; + OrganizationId id = 1 [(required) = true]; // Name of the GitHub organization. string name = 2 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index 477eef9c..a899245f 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -41,7 +41,7 @@ message OrganizationInit { option (entity).kind = PROCESS_MANAGER; option (entity).visibility = FULL; - // The ID of the organization for which the initialization is performed. + // The organization for which the initialization is performed. OrganizationId organization = 1; // Name of the Google Chat space associated with the organization in form `spaces/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index b1fd3d8c..c97792b7 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -35,7 +35,7 @@ import "spine/chatbot/github/identifiers.proto"; // Initialize watched organization resources command. message InitializeOrganization { - // ID of the organization to perform initialization for. + // The organization to perform initialization for. OrganizationId organization = 1 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 1c0b1b05..2a0d5cda 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -32,7 +32,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// A GitHub organization. +// Organization repositories. message OrganizationRepositories { option (entity).kind = PROJECTION; option (entity).visibility = FULL; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index 506f0a16..a937df86 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -39,7 +39,7 @@ message Repository { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - RepositoryId repository = 1; + RepositoryId id = 1; // Name of the repository. string name = 2; @@ -50,6 +50,6 @@ message Repository { // Travis CI URL of the repository. spine.net.Url travis_ci_url = 4; - // ID of the organization repository is related to if any. + // The organization repository is related to, if any. OrganizationId organization = 5; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 356a2bee..35e7a336 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -35,10 +35,10 @@ import "spine/chatbot/github/identifiers.proto"; // Check repository CI build state command. message CheckRepositoryBuild { - // ID of the repository to perform a check for. + // The repository to perform a check for. RepositoryId repository = 1 [(required) = true]; - // ID of the organization the repository belongs to. + // The organization the repository belongs to. OrganizationId organization = 2 [(required) = true]; // Name of the Google Chat space associated with the organization in form `spaces/`. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index a266ae2b..86fb576b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -37,7 +37,7 @@ message Space { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - SpaceId space = 1; + SpaceId id = 1; // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 7d7d7f28..55396926 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -35,7 +35,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // Register Chat space command. message RegisterSpace { - SpaceId space = 1 [(required) = true]; + SpaceId id = 1 [(required) = true]; // Whether the space is a DM between a bot and a single human. bool single_user_bot_dm = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index cd277b8b..ff43f109 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -37,15 +37,15 @@ message Thread { option (entity).kind = AGGREGATE; option (entity).visibility = FULL; - ThreadId thread = 1; + ThreadId id = 1; // Resource name of the thread. ThreadResource resource = 2; - // ID of the space within with the thread is available. + // The space within with the thread is available. SpaceId space = 3; - // IDs of the messages posted by the bot to the thread. + // Messages posted by the bot to the thread. repeated MessageId messages = 4; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto index d6407adc..e48197c5 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -46,6 +46,6 @@ message ThreadChat { // Chat thread. ThreadResource resource = 2; - // ID of the space within with the thread is available. + // Space within with the thread is available. SpaceId space = 3; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto index d5adf3f7..ac0e2686 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_events.proto @@ -41,7 +41,7 @@ message ThreadInitialized { // Chat thread. ThreadResource resource = 2 [(required) = true]; - // ID of the space within which the thread is available. + // Space within which the thread is available. SpaceId space = 3 [(required) = true]; } @@ -50,6 +50,6 @@ message MessageAdded { MessageId message = 1 [(required) = true]; - // ID of the thread to which the message is added. + // Thread to which the message is added. ThreadId thread = 2 [(required) = true]; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 4502ff93..f06db20a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -53,7 +53,7 @@ final class Register { void setUp() { var registerOrganization = RegisterOrganization .newBuilder() - .setOrganization(organization) + .setId(organization) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setWebsiteUrl(websiteUrl) @@ -83,7 +83,7 @@ void producingEvent() { void settingState() { var expectedState = Organization .newBuilder() - .setOrganization(organization) + .setId(organization) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setWebsiteUrl(websiteUrl) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 8df31fbd..a8a1ae0f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -85,7 +85,7 @@ void producingEvent() { void settingState() { var expectedState = Repository .newBuilder() - .setRepository(repository) + .setId(repository) .setGithubUrl(githubUrl) .setTravisCiUrl(travisCiUrl) .setName(REPO_NAME) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 3b02b5b0..577403cc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -50,7 +50,7 @@ final class Register { void setUp() { var registerSpace = RegisterSpace .newBuilder() - .setSpace(SPACE) + .setId(SPACE) .setThreaded(true) .setDisplayName(DISPLAY_NAME) .vBuild(); @@ -74,7 +74,7 @@ void producingEvent() { void settingState() { var expectedState = Space .newBuilder() - .setSpace(SPACE) + .setId(SPACE) .setThreaded(true) .setDisplayName(DISPLAY_NAME) .vBuild(); @@ -122,7 +122,7 @@ void producingEvent() { void settingState() { var expectedState = Space .newBuilder() - .setSpace(SPACE) + .setId(SPACE) .setThreaded(true) .setDisplayName(DISPLAY_NAME) .vBuild(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index ff83e08d..20f461ad 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -79,7 +79,7 @@ void producingEvent() { void settingState() { var state = Thread .newBuilder() - .setThread(thread) + .setId(thread) .setSpace(space) .setResource(resource) .vBuild(); @@ -132,7 +132,7 @@ void producingEvent() { void settingState() { var state = Thread .newBuilder() - .setThread(thread) + .setId(thread) .setSpace(space) .setResource(threadResource) .addMessages(message) From 0ce607f33c557174b7f10edc26e08fbb399ddb2a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 18:40:58 +0300 Subject: [PATCH 279/492] Rename ChatBotServerClient to Client --- .../spine/chatbot/RepositoriesController.java | 17 ++++---- .../{ChatBotServerClient.java => Client.java} | 43 ++++++------------- 2 files changed, 21 insertions(+), 39 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/client/{ChatBotServerClient.java => Client.java} (75%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 0d2f944d..92c50d6a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -22,7 +22,7 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; -import io.spine.chatbot.client.ChatBotServerClient; +import io.spine.chatbot.client.Client; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; @@ -43,16 +43,17 @@ final class RepositoriesController implements Logging { @Post("/builds/check") String checkBuildStatuses() { _debug().log("Checking repositories build statues."); - var botClient = ChatBotServerClient.inProcessClient(SERVER_NAME); - var organizations = botClient.listOrganizations(); - for (var organization : organizations) { - var repos = botClient.listOrgRepos(organization.getId()); - repos.forEach(repo -> checkBuildStatus(botClient, repo, organization)); + try (var client = Client.inProcessClient(SERVER_NAME)) { + var organizations = client.listOrganizations(); + for (var organization : organizations) { + var repos = client.listOrgRepos(organization.getId()); + repos.forEach(repo -> checkBuildStatus(client, repo, organization)); + } + return "success"; } - return "success"; } - private void checkBuildStatus(ChatBotServerClient botClient, + private void checkBuildStatus(Client botClient, RepositoryId repository, Organization organization) { _info().log("Sending `CheckRepositoryBuild` command for repository `%s`", diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java similarity index 75% rename from google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index 3dc74e81..2681460e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/ChatBotServerClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -28,38 +28,35 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; -import io.spine.client.Client; import io.spine.client.ClientRequest; import io.spine.client.CommandRequest; import io.spine.client.Subscription; -import java.util.Collection; import java.util.concurrent.CountDownLatch; import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableList.toImmutableList; /** * A ChatBot application's Spine client. * - *

Abstracts working with Spine's {@link Client client}. + *

Abstracts working with Spine's {@link io.spine.client.Client client}. */ -public final class ChatBotServerClient { +public final class Client implements AutoCloseable { - private final Client client; + private final io.spine.client.Client client; - private ChatBotServerClient(Client client) { + private Client(io.spine.client.Client client) { this.client = client; } /** * Creates a new in-process client configured for the specified server. */ - public static ChatBotServerClient inProcessClient(String serverName) { - Client client = Client + public static Client inProcessClient(String serverName) { + io.spine.client.Client client = io.spine.client.Client .inProcess(serverName) .build(); - return new ChatBotServerClient(client); + return new Client(client); } /** @@ -103,27 +100,6 @@ public ImmutableList listOrgRepos(OrganizationId organization) { .getRepositoriesList()); } - /** - * Returns IDs for all registered repositories. - */ - public ImmutableList listRepositories() { - var orgIds = client.asGuest() - .select(Organization.class) - .run() - .stream() - .map(Organization::getId) - .collect(toImmutableList()); - var orgRepos = client.asGuest() - .select(OrganizationRepositories.class) - .byId(orgIds) - .run(); - var result = orgRepos.stream() - .map(OrganizationRepositories::getRepositoriesList) - .flatMap(Collection::stream) - .collect(toImmutableList()); - return result; - } - /** * Posts a command and waits synchronously till the expected outcome event is published. */ @@ -146,4 +122,9 @@ public void post(CommandMessage command, Class expec } subscriptions.forEach(this::cancelSubscription); } + + @Override + public void close() { + this.client.close(); + } } From 5f0647774b66c24011eddcde46feb14a3fcf5cc9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 18:41:10 +0300 Subject: [PATCH 280/492] Cleanup docs --- .../main/java/io/spine/chatbot/delivery/package-info.java | 2 +- .../chatbot/server/google/chat/IncomingEventsHandler.java | 6 +++--- .../spine/chatbot/server/google/chat/ThreadAggregate.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java index 35b379c6..02227dfc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java @@ -19,7 +19,7 @@ */ /** - * This package contains Spine's Google Chat Bot signals delivery configurations. + * This package contains the ChatBot signals delivery configurations. */ @CheckReturnValue @ParametersAreNonnullByDefault diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 876b0ee7..e3e77f3a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -40,10 +40,10 @@ *

Processes incoming {@link ChatEvent} message and emits one of the following domain events: * *

    - *
  • {@link BotAddedToSpace} — the ChatBot is added to a Google Chat space; - *
  • {@link BotRemovedFromSpace} — the ChatBot is removed from the Google Chat space; + *
  • {@link BotAddedToSpace} — the ChatBot is added to a space; + *
  • {@link BotRemovedFromSpace} — the ChatBot is removed from the space; *
  • {@link MessageReceived} — the ChatBot received a new incoming message from a user - * within a Google Chat space. + * within a space. *
* *

If the bot receives a chat event with a not supported currently event type, diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index 059b73db..455341b8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -32,7 +32,7 @@ import io.spine.server.event.React; /** - * A thread in the Google Chat room. + * A thread in the chat room. * *

A new thread is initialized as early as a new conversation is started in the room. * It is being initialized with the creation of the first message of the conversation. From 28372dbb125fc7f4b02778289e4856dc8fb4c204 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 18:51:21 +0300 Subject: [PATCH 281/492] Extract space mixin --- .../server/google/chat/SpaceAggregate.java | 7 +-- .../google/chat/incoming/SpaceMixin.java | 43 +++++++++++++++++++ .../google/chat/incoming/package-info.java | 30 +++++++++++++ .../incoming/incoming_chat_messages.proto | 2 + 4 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index e6afa1a4..a685c50f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -24,7 +24,6 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; -import io.spine.chatbot.google.chat.incoming.SpaceType; import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import io.spine.logging.Logging; import io.spine.server.aggregate.Aggregate; @@ -53,7 +52,7 @@ SpaceRegistered on(BotAddedToSpace e) { .newBuilder() .setSpace(spaceId) .setDisplayName(displayName) - .setThreaded(isThreaded(space)) + .setThreaded(space.isThreaded()) .vBuild(); } @@ -80,8 +79,4 @@ private void on(SpaceRegistered e) { .setSingleUserBotDm(e.getSingleUserBotDm()) .setThreaded(e.getThreaded()); } - - private static boolean isThreaded(io.spine.chatbot.google.chat.incoming.Space space) { - return space.getType() == SpaceType.ROOM; - } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java new file mode 100644 index 00000000..096b1f8a --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat.incoming; + +import io.spine.chatbot.google.chat.incoming.SpaceType; + +/** + * Provides utility helpers for the {@link io.spine.chatbot.google.chat.incoming.Space Space} type. + */ +public interface SpaceMixin { + + /** + * Determines whether a space is threaded. + * + * @return `true` if the space is threaded, `false otherwise + */ + default boolean isThreaded() { + return getType() == SpaceType.ROOM; + } + + /** + * Returns space type. + */ + SpaceType getType(); +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java new file mode 100644 index 00000000..a598a2c9 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains entities related to the Google Chat incoming events handling. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.server.google.chat.incoming; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 7884a30d..80ff1cfa 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -133,6 +133,8 @@ message Message { // A room or DM in Chat. message Space { + option (is).java_type = "io.spine.chatbot.server.google.chat.incoming.SpaceMixin"; + // Resource name of the space, in the form "spaces/*". string name = 1 [(required) = true, (pattern).regex = "spaces/.+"]; From 79a3718ddbdac5d419df8a701183d54acc566de5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:01:58 +0300 Subject: [PATCH 282/492] Add missing GeneratedMixin annotation --- .../spine/chatbot/server/google/chat/incoming/SpaceMixin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java index 096b1f8a..ed611984 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java @@ -20,11 +20,13 @@ package io.spine.chatbot.server.google.chat.incoming; +import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.google.chat.incoming.SpaceType; /** * Provides utility helpers for the {@link io.spine.chatbot.google.chat.incoming.Space Space} type. */ +@GeneratedMixin public interface SpaceMixin { /** From 5c34ad8b4d1cdd83f8e28358fff9cd1bd94c1abf Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:13:02 +0300 Subject: [PATCH 283/492] Add links to the references --- .../incoming/incoming_chat_messages.proto | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 80ff1cfa..b35e07e6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -38,7 +38,11 @@ option java_outer_classname = "IncomingChatMessagesProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -// A Chat incoming event. +// An incoming Chat event. +// +// The definition conforms to the JSON representation defined in the +// . +// message ChatEvent { option (is).java_type = "io.spine.base.EventMessage"; @@ -71,6 +75,10 @@ message ChatEvent { } // A message in Chat. +// +// See +// reference declaration for more details. +// message Message { // Resource name, in the form "spaces/*/messages/*". @@ -131,6 +139,10 @@ message Message { } // A room or DM in Chat. +// +// See +// reference declaration for more details. +// message Space { option (is).java_type = "io.spine.chatbot.server.google.chat.incoming.SpaceMixin"; @@ -146,6 +158,10 @@ message Space { } // A user in Chat. +// +// See reference +// declaration for more details. +// message User { // Resource name, in the format "users/*". @@ -177,6 +193,10 @@ enum SpaceType { } // The type of the event the bot is receiving. +// +// See reference +// declaration for more details. +// enum EventType { ET_UNKNOWN = 0; From e3eb52ff84a4200980449bb80172c6471bef6705 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:17:49 +0300 Subject: [PATCH 284/492] Add links to the API references --- .../proto/spine/chatbot/travis/travis.proto | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 0fc1a6d3..448f69f2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -40,6 +40,8 @@ option java_generate_equals_and_hash = true; // The owner of a resource. // // This will be either a user or an organization. +// See reference declaration +// for more details. // message Owner { @@ -51,6 +53,10 @@ message Owner { } // An individual repository. +// +// See reference +// declaration for more details. +// message Repository { // Value uniquely identifying the repository. @@ -67,6 +73,10 @@ message Repository { } // The branch of a repository. +// +// See reference declaration +// for more details. +// message Branch { // Name of the git branch. @@ -74,6 +84,10 @@ message Branch { } // Commit information is obtained by requesting a build. +// +// See reference declaration +// for more details. +// message Commit { // Value uniquely identifying the commit. @@ -106,6 +120,10 @@ message Commit { } // Minimal Travis CI build representation. +// +// See reference declaration +// for more details. +// message Build { // Value uniquely identifying the build. @@ -143,6 +161,10 @@ message Build { } // A Travis `branch` API endpoint response. +// +// See API reference for more +// details. +// message RepoBranchBuildResponse { option (is).java_type = "TravisResponse"; @@ -164,6 +186,10 @@ message RepoBranchBuildResponse { } // A Travis `repos` API endpoint response. +// +// See API reference +// for more details. +// message RepositoriesResponse { option (is).java_type = "TravisResponse"; From da4dcd4d2f23d1f0621c51133c8e2790790d7ffe Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:46:51 +0300 Subject: [PATCH 285/492] Drop trailing dot --- .../src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index b3a1cb31..2c57bc88 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -23,7 +23,7 @@ /** * Travis CI branch builds API query. * - * @see Find branch build. + * @see Find branch build */ public final class BuildsQuery extends Query { From e2215afeadb3a3b4d473bd14a01d34b1cae4583a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:49:06 +0300 Subject: [PATCH 286/492] Add missing notNull checks --- .../src/main/java/io/spine/chatbot/client/Client.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index 2681460e..f2a4a92a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -34,6 +34,7 @@ import java.util.concurrent.CountDownLatch; +import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; /** @@ -53,6 +54,7 @@ private Client(io.spine.client.Client client) { * Creates a new in-process client configured for the specified server. */ public static Client inProcessClient(String serverName) { + checkNotNull(serverName); io.spine.client.Client client = io.spine.client.Client .inProcess(serverName) .build(); @@ -74,6 +76,7 @@ public ClientRequest asGuest() { */ @CanIgnoreReturnValue public boolean cancelSubscription(Subscription subscription) { + checkNotNull(subscription); return client.subscriptions() .cancel(subscription); } @@ -91,6 +94,7 @@ public ImmutableList listOrganizations() { * Returns list of all registered repositories for the {@code organization}. */ public ImmutableList listOrgRepos(OrganizationId organization) { + checkNotNull(organization); var orgRepos = client.asGuest() .select(OrganizationRepositories.class) .byId(organization) @@ -104,6 +108,8 @@ public ImmutableList listOrgRepos(OrganizationId organization) { * Posts a command and waits synchronously till the expected outcome event is published. */ public void post(CommandMessage command, Class expectedOutcome) { + checkNotNull(command); + checkNotNull(expectedOutcome); post(command, expectedOutcome, 1); } From 90856e2ea31193679e550e8985ffe636ec1b3360 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:49:49 +0300 Subject: [PATCH 287/492] cleanu formatting --- .../src/main/java/io/spine/chatbot/client/Client.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index f2a4a92a..3599f6c4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -116,11 +116,10 @@ public void post(CommandMessage command, Class expec private void post(CommandMessage command, Class expectedOutcome, int expectedEvents) { var latch = new CountDownLatch(expectedEvents); - var subscriptions = client - .asGuest() - .command(command) - .observe(expectedOutcome, event -> latch.countDown()) - .post(); + var subscriptions = client.asGuest() + .command(command) + .observe(expectedOutcome, event -> latch.countDown()) + .post(); try { latch.await(); } catch (InterruptedException e) { From e8d1e58a4995ac2d86b00a84c0f653e890c1bfd4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 19:54:41 +0300 Subject: [PATCH 288/492] Simplify client and drop unused methods. --- .../spine/chatbot/RepositoriesController.java | 14 +---- .../java/io/spine/chatbot/client/Client.java | 62 ++++++++++++------- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 92c50d6a..72386651 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -29,7 +29,6 @@ import io.spine.logging.Logging; import static io.spine.chatbot.Application.SERVER_NAME; -import static io.spine.util.Exceptions.newIllegalStateException; /** * A REST controller handling Repository commands. @@ -59,18 +58,7 @@ private void checkBuildStatus(Client botClient, _info().log("Sending `CheckRepositoryBuild` command for repository `%s`", repository.getValue()); var checkRepositoryBuild = checkRepoBuildCommand(repository, organization); - var subscriptions = botClient - .asGuest() - .command(checkRepositoryBuild) - .onStreamingError(RepositoriesController::throwProcessingError) - .post(); - subscriptions.forEach(botClient::cancelSubscription); - } - - private static void throwProcessingError(Throwable throwable) { - throw newIllegalStateException( - throwable, "An error while processing the command." - ); + botClient.post(checkRepositoryBuild); } private static CheckRepositoryBuild diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index 3599f6c4..537c773e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -28,7 +28,6 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; -import io.spine.client.ClientRequest; import io.spine.client.CommandRequest; import io.spine.client.Subscription; @@ -36,6 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static io.spine.util.Exceptions.newIllegalStateException; /** * A ChatBot application's Spine client. @@ -61,26 +61,6 @@ public static Client inProcessClient(String serverName) { return new Client(client); } - /** - * Returns Spine client guest request. - */ - public ClientRequest asGuest() { - return client.asGuest(); - } - - /** - * Cancels the passed subscription. - * - * @see io.spine.client.Subscriptions#cancel(Subscription) - * @see CommandRequest#post() - */ - @CanIgnoreReturnValue - public boolean cancelSubscription(Subscription subscription) { - checkNotNull(subscription); - return client.subscriptions() - .cancel(subscription); - } - /** * Retrieves all registered organizations. */ @@ -104,6 +84,11 @@ public ImmutableList listOrgRepos(OrganizationId organization) { .getRepositoriesList()); } + @Override + public void close() { + this.client.close(); + } + /** * Posts a command and waits synchronously till the expected outcome event is published. */ @@ -113,11 +98,26 @@ public void post(CommandMessage command, Class expec post(command, expectedOutcome, 1); } + /** + * Posts a command asynchronously. + * + * @see #post(CommandMessage, Class) + */ + public void post(CommandMessage command) { + checkNotNull(command); + var subscriptions = client.asGuest() + .command(command) + .onStreamingError(Client::throwProcessingError) + .post(); + subscriptions.forEach(this::cancelSubscription); + } + private void post(CommandMessage command, Class expectedOutcome, int expectedEvents) { var latch = new CountDownLatch(expectedEvents); var subscriptions = client.asGuest() .command(command) + .onStreamingError(Client::throwProcessingError) .observe(expectedOutcome, event -> latch.countDown()) .post(); try { @@ -128,8 +128,22 @@ public void post(CommandMessage command, Class expec subscriptions.forEach(this::cancelSubscription); } - @Override - public void close() { - this.client.close(); + /** + * Cancels the passed subscription. + * + * @see io.spine.client.Subscriptions#cancel(Subscription) + * @see CommandRequest#post() + */ + @CanIgnoreReturnValue + private boolean cancelSubscription(Subscription subscription) { + checkNotNull(subscription); + return client.subscriptions() + .cancel(subscription); + } + + private static void throwProcessingError(Throwable throwable) { + throw newIllegalStateException( + throwable, "An error while processing the command." + ); } } From 59f20e891d9588e1f3c431bbb7d84c794bd0a9d1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 22:12:40 +0300 Subject: [PATCH 289/492] Add missing notNull checks --- .../java/io/spine/chatbot/server/github/GitHubIdentifier.java | 4 ++++ google-chat-bot/src/main/java/io/spine/net/Urls.java | 1 + 2 files changed, 5 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java index e2ab6b46..31e71b63 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java @@ -23,6 +23,8 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; +import static com.google.common.base.Preconditions.checkNotNull; + /** * A utility for working with {@link GitHubContext} identifiers. */ @@ -38,6 +40,7 @@ private GitHubIdentifier() { * Creates a new {@link OrganizationId} out of the specified {@code name}. */ public static OrganizationId organization(String name) { + checkNotNull(name); return OrganizationId .newBuilder() .setValue(name) @@ -48,6 +51,7 @@ public static OrganizationId organization(String name) { * Creates a new {@link RepositoryId} out of the specified {@code slug}. */ public static RepositoryId repository(String slug) { + checkNotNull(slug); return RepositoryId .newBuilder() .setValue(slug) diff --git a/google-chat-bot/src/main/java/io/spine/net/Urls.java b/google-chat-bot/src/main/java/io/spine/net/Urls.java index 85f93861..647f482d 100644 --- a/google-chat-bot/src/main/java/io/spine/net/Urls.java +++ b/google-chat-bot/src/main/java/io/spine/net/Urls.java @@ -41,6 +41,7 @@ private Urls() { * Creates a new {@link Url} out of supplied spec. */ public static Url urlOfSpec(String spec) { + checkNotNull(spec); return Url.newBuilder() .setSpec(spec) .vBuild(); From edd7b1379ea36562aada20663f84edca8465b3f6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 22:14:14 +0300 Subject: [PATCH 290/492] Add missing docs --- .../spine/chatbot/server/github/GitHubContext.java | 3 +++ .../chatbot/server/github/RepoBuildProcess.java | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 2ee5459e..7d0a22ad 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -74,6 +74,9 @@ public static final class Builder { private TravisClient travisClient; + /** + * Prevents direct instantiation. + */ private Builder() { } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 09db3f8e..eb2daec6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -85,14 +85,14 @@ final class RepoBuildProcess @Assign EitherOf3 handle(CheckRepositoryBuild c) throws NoBuildsFound { - var repositoryId = c.getRepository(); - _info().log("Checking build status for repository `%s`.", repositoryId.getValue()); - var branchBuild = client.execute(BuildsQuery.forRepo(repositoryId.getValue())); + var repository = c.getRepository(); + _info().log("Checking build status for repository `%s`.", repository.getValue()); + var branchBuild = client.execute(BuildsQuery.forRepo(repository.getValue())); if (isDefault(branchBuild.getLastBuild())) { - _warn().log("No builds found for the repository `%s`.", repositoryId.getValue()); + _warn().log("No builds found for the repository `%s`.", repository.getValue()); throw NoBuildsFound .newBuilder() - .setRepository(repositoryId) + .setRepository(repository) .build(); } var buildState = buildStateFrom(branchBuild, c.getGoogleChatSpace()); @@ -104,7 +104,7 @@ EitherOf3 handle(CheckRepositoryBuild .setPreviousValue(state().getBuildState()) .setNewValue(buildState) .vBuild(); - var result = determineOutcome(repositoryId, stateChange); + var result = determineOutcome(repository, stateChange); return result; } From 3d6c2f9ea2286272b4397345e45ee645bc5bd0eb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 22:17:35 +0300 Subject: [PATCH 291/492] Set cause for the log --- .../java/io/spine/chatbot/api/google/chat/GoogleChat.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 32796baa..d858a522 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -86,7 +86,9 @@ private Message sendMessage(String space, Message message) { .create(space, message) .execute(); } catch (IOException e) { - _error().log("Unable to send message to space `%s`.", space, e); + logger().atSevere() + .withCause(e) + .log("Unable to send message to space `%s`.", space); throw new RuntimeException("Unable to send message to space " + space, e); } } @@ -107,7 +109,8 @@ private static HangoutsChat hangoutsChat() { String message = "Unable to create Hangouts Chat client."; Logging.loggerFor(GoogleChat.class) .atSevere() - .log(message, e); + .withCause(e) + .log(message); throw new RuntimeException(message, e); } } From 8fa9b8ed78c3ad1a6b9068d34688a6b534e78e1f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 24 Jun 2020 22:34:30 +0300 Subject: [PATCH 292/492] use shorter utilities --- .../chatbot/server/github/OrganizationAggregateTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index f06db20a..8e6b3898 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -31,6 +31,8 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.GitHubIdentifier.organization; +import static io.spine.net.Urls.githubUrlFor; +import static io.spine.net.Urls.travisUrlFor; import static io.spine.net.Urls.urlOfSpec; @DisplayName("OrganizationAggregate should") @@ -45,8 +47,8 @@ final class Register { private final OrganizationId organization = organization("TestOrganization"); - private final Url githubUrl = urlOfSpec("https://github.com/TestOrganization"); - private final Url travisCiUrl = urlOfSpec("https://travis-ci.com/TestOrganization"); + private final Url githubUrl = githubUrlFor(organization.getValue()); + private final Url travisCiUrl = travisUrlFor(organization.getValue()); private final Url websiteUrl = urlOfSpec("https://test-organization.com"); @BeforeEach From 36f4c393ac313fe343148005b9b90b9979f37fe1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 11:54:04 +0300 Subject: [PATCH 293/492] Use separate dedicated non-app-default service account for Google Chat. It looks like Google Chat API could not be used with **any** default account, either a user account or a GCP default service account. See https://stackoverflow.com/questions/62571412/hangout-chat-api-authentication-fails-with-default-service-account for details. --- .../chatbot/api/google/chat/GoogleChat.java | 11 +++++++- .../chatbot/api/google/secret/Secrets.java | 25 +++++++++++++++---- .../chatbot/IncomingEventsControllerTest.java | 2 ++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index d858a522..6717efe3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -27,11 +27,15 @@ import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.spine.chatbot.api.google.secret.Secrets; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.logging.Logging; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; import java.security.GeneralSecurityException; import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; @@ -95,7 +99,8 @@ private Message sendMessage(String space, Message message) { private static HangoutsChat hangoutsChat() { try { - var credentials = GoogleCredentials.getApplicationDefault() + var serviceAccount = Secrets.chatServiceAccount(); + var credentials = GoogleCredentials.fromStream(streamFrom(serviceAccount)) .createScoped(CHAT_BOT_SCOPE); var credentialsAdapter = new HttpCredentialsAdapter(credentials); var chat = new HangoutsChat.Builder( @@ -114,4 +119,8 @@ private static HangoutsChat hangoutsChat() { throw new RuntimeException(message, e); } } + + private static InputStream streamFrom(String data) { + return new ByteArrayInputStream(data.getBytes(Charset.defaultCharset())); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java index ba127e53..b8a260b6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java @@ -24,7 +24,8 @@ import com.google.cloud.secretmanager.v1.SecretVersionName; import java.io.IOException; -import java.nio.charset.Charset; + +import static io.spine.util.Exceptions.newIllegalStateException; /** * Utility for accessing application secrets stored in Google Secret Manager. @@ -34,6 +35,7 @@ public final class Secrets { @SuppressWarnings("CallToSystemGetenv") private static final String PROJECT_ID = System.getenv("GCP_PROJECT_ID"); private static final String TRAVIS_API_TOKEN = "TravisApiToken"; + private static final String CHAT_SERVICE_ACCOUNT = "ChatServiceAccount"; /** * Prevents direct instantiation of the utility class. @@ -42,18 +44,31 @@ private Secrets() { } /** - * Returns Travis CI API access token. + * Retrieves the Travis CI API access token. */ public static String travisToken() { + var result = retrieveSecret(TRAVIS_API_TOKEN); + return result; + } + + /** + * Retrieves the Google Chat API service account. + */ + public static String chatServiceAccount() { + var result = retrieveSecret(CHAT_SERVICE_ACCOUNT); + return result; + } + + private static String retrieveSecret(String secretName) { try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { - var secretVersion = SecretVersionName.of(PROJECT_ID, TRAVIS_API_TOKEN, "latest"); + var secretVersion = SecretVersionName.of(PROJECT_ID, secretName, "latest"); var secret = client.accessSecretVersion(secretVersion) .getPayload() .getData() - .toString(Charset.defaultCharset()); + .toStringUtf8(); return secret; } catch (IOException e) { - throw new RuntimeException("Unable to retrieve Travis API key.", e); + throw newIllegalStateException(e, "Unable to retrieve secret `%s`.", secretName); } } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 07d6e21e..5049681e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -27,6 +27,7 @@ import io.micronaut.http.client.annotation.Client; import io.micronaut.runtime.server.EmbeddedServer; import io.micronaut.test.annotation.MicronautTest; +import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; import io.spine.chatbot.api.travis.InMemoryTravisClient; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; @@ -57,6 +58,7 @@ final class IncomingEventsControllerTest { static void setupServer() { var chatContext = GoogleChatContext .newBuilder() + .setGoogleChatClient(InMemoryGoogleChatClient.lenientClient()) .build(); var gitHubContext = GitHubContext .newBuilder() From b2cef693a1bad81dce1dccb8ec733ccc40e11aa3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 13:04:40 +0300 Subject: [PATCH 294/492] Add Cloud Run and Cloud Build sections --- ENVIRONMENT.md | 55 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index b2bfbb55..33067e7c 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -4,6 +4,42 @@ Cloud Environment setup The ChatBot application is working in the cloud environment on the Google Cloud Platform (GCP) and this document provides an overview of the currently configured environment. +## Cloud Run + +We use [Cloud Run][cloud-run] as our main compute platform for the ChatBot application. +Cloud Run is a managed serverless solution that works with Docker images and could scale +the load when needed. + +In Cloud Run we configure a `chat-bot-server` service with the +`gcr.io//chat-bot-server` container image. The image is built automatically using +`jib` Gradle plugin and deployed to the [Container Registry][container-registry] for our needs +as part of the build process. + +Upon pushes to the `master` branch, the Cloud Build performs the automatic deployment of the +new Cloud Run revision. (see [Cloud Build](#cloud-build) section for details). + +[cloud-run]: https://cloud.google.com/run +[jib]: https://github.com/GoogleContainerTools/jib +[container-registry]: https://cloud.google.com/container-registry + +## Cloud Build + +We use [Cloud Build] CI/CD solution to continuously build and deploy our application. + +The Cloud Build configuration is available as [`cloudbuild.yaml`](./cloudbuild.yaml) and does +the following: + +1. Starts the Gradle build for the project. +2. Deploys the new revision of the Cloud Run service. + +In addition to the configuration, we create a Cloud Build trigger to automatically start build +and deploy process upon commits to the `master` branch. + +The Cloud Build itself uses GCP service accounts in order to access the APIs and should be +configured to allow the Cloud Run deployment. See the [IAM](#iam) section for details. + +[cloud-build]: https://cloud.google.com/cloud-build +[cloud-build-trigger]: https://cloud.google.com/cloud-build/docs/automating-builds/create-manage-triggers#console ## Hangouts Chat API @@ -36,8 +72,9 @@ At the moment of writing, the app requires the following Pub/Sub topics to be co topic. For the topic we configure the `incoming-bot-messages-cloud-run` push subscription that - delivers messages to the `/chat/incoming/event` endpoint. The subscription is configured - with a backoff retry policy and the acknowledgement deadline of 600 seconds. + delivers messages to the `/chat/incoming/event` endpoint of the Cloud Run [service](#cloud-run). + We configure The subscription with a backoff retry policy and the acknowledgement + deadline of 600 seconds. Also, the `dead lettering` is configured for the subscription, so all the undelivered messages are sent to our next topic — `dead-incoming-bot-messages`. @@ -54,8 +91,9 @@ At the moment of writing, the app requires the following Pub/Sub topics to be co build state (see [Cloud Scheduler](#cloud-scheduler) section for details) For the topic we configure the `repository-checks-cloud-run` subscription that delivers messages - to the `/repositories/builds/check`. The subscription uses the same `cloud-run-pubsub-invoker` - service account as the `incoming-bot-messages-cloud-run` (see [IAM](#iam) section for details). + to the `/repositories/builds/check` endpoint of the Cloud Run [service](#cloud-run). + The subscription uses the same `cloud-run-pubsub-invoker` service account as the + `incoming-bot-messages-cloud-run` (see [IAM](#iam) section for details). [pubsub]: https://cloud.google.com/pubsub @@ -72,13 +110,4 @@ to run every hour using the following unix-cron format expression: `0 * * * *`. [scheduler]: https://cloud.google.com/scheduler -## Cloud Run - -We use Cloud Run as our main compute platform for the ChatBot application. Cloud Run is a managed -serverless solution that works with Docker. - -//TODO:2020-06-23:ysergiichuk: describe Cloud run usage. - //TODO:2020-06-23:ysergiichuk: add IAM section. - -//TODO:2020-06-23:ysergiichuk: add Cloud Build section. From 366a2ad812f7697e8f01fe3b02971e41fd654a64 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 13:07:22 +0300 Subject: [PATCH 295/492] Add link to pubsub bot guide --- ENVIRONMENT.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 33067e7c..64f31e0a 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -50,14 +50,15 @@ The bot configuration could be done only via the web UI console as of the writin in accordance to the publishing [guide][publishing-guide] where the essential configurations are: 1. `Functionality` — check `Bot works in rooms`. We do not expect the bot to work in direct messages. -2. `Connection settings` — choose `Cloud Pub/Sub` and enter a Pub/Sub topic name that'd be used - to deliver messages from users to the bot. (for the Pub/Sub details see +2. `Connection settings` — choose [`Cloud Pub/Sub`][pubsub-bot] and enter a Pub/Sub topic name + that'd be used to deliver messages from users to the bot. (for the Pub/Sub details see [Pub/Sub](#pubsub) section) 3. `Permissions` — choose `Specific people and groups in your domain` and list individuals or groups in the domain who'd be able to install the bot. [chat-api]: https://developers.google.com/hangouts/chat [publishing-guide]: https://developers.google.com/hangouts/chat/how-tos/bots-publish +[pubsub-bot]: https://developers.google.com/hangouts/chat/how-tos/pub-sub ## Pub/Sub From c80929d59fa13e8833bd985a9616c33f3d6b88ca Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 13:13:52 +0300 Subject: [PATCH 296/492] Add Secret Manager section --- ENVIRONMENT.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 64f31e0a..9103ddbc 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -111,4 +111,18 @@ to run every hour using the following unix-cron format expression: `0 * * * *`. [scheduler]: https://cloud.google.com/scheduler +## Secret Manager + +To be able to use API tokens and service accounts securely in the application, +we use [Secret Manager][secret-manager] service that allows managing and rotate secrets with ease. + +We [manage][managing-secrets] secrets using the Secret Manager Web UI, but in order to be able +to [read][reading-secrets] the secrets, developers and service accounts should have the +`roles/secretmanager.viewer` role that is not available by default (see [IAM](#iam) section +for details). + +[secret-manager]: https://cloud.google.com/secret-manager +[managing-secrets]: https://cloud.google.com/secret-manager/docs/managing-secrets +[reading-secrets]: https://cloud.google.com/secret-manager/docs/managing-secret-versions#get + //TODO:2020-06-23:ysergiichuk: add IAM section. From 2ef9cb6aee735aecc03aae6d3829df8392d55c58 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 16:45:09 +0300 Subject: [PATCH 297/492] Add stub IAM section. --- ENVIRONMENT.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 9103ddbc..bb0b7a4c 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -125,4 +125,27 @@ for details). [managing-secrets]: https://cloud.google.com/secret-manager/docs/managing-secrets [reading-secrets]: https://cloud.google.com/secret-manager/docs/managing-secret-versions#get -//TODO:2020-06-23:ysergiichuk: add IAM section. +## IAM + +Google [Cloud Identity and Access Management][iam] (IAM) lets us to fine-tune the authorization and +access management for the application. + +In order to run the application we configure the following service account and their respective +roles: + +1. `chat-api-push@system.gserviceaccount.com` — a special Chat API service account used by the + Chat to publish messages to the Pub/Sub topic. +2. `spine-chat-bot-actor@.iam.gserviceaccount.com` — the custom service account we're + using as the credentials for the Chat API used by the bot. The Hangouts Chat API works only + with dedicate service account keys and could not be used with default credentials. +3. `-compute@developer.gserviceaccount.com` — default compute service account used by + Cloud Run. +4. `@cloudbuild.gserviceaccount.com` — Cloud Build service account used by the + Cloud Build service to build and deploy the application. +5. `cloud-run-pubsub-invoker@.iam.gserviceaccount.com` — a custom service account we're + using to call the Cloud Run service from the Pub/Sub subscriptions. The Cloud Run + is not accepting unauthenticated calls by default and is not exposed to the internet. + +//TODO:2020-06-25:ysergiichuk: add roles/descriptions for service accounts + +[iam]: https://cloud.google.com/iam \ No newline at end of file From a6b47c1131aea1ede0fc069150339d3329c327c3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 17:57:30 +0300 Subject: [PATCH 298/492] Add IAM service account details --- ENVIRONMENT.md | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index bb0b7a4c..ee1ed4af 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -135,17 +135,44 @@ roles: 1. `chat-api-push@system.gserviceaccount.com` — a special Chat API service account used by the Chat to publish messages to the Pub/Sub topic. -2. `spine-chat-bot-actor@.iam.gserviceaccount.com` — the custom service account we're - using as the credentials for the Chat API used by the bot. The Hangouts Chat API works only - with dedicate service account keys and could not be used with default credentials. + + We [must][grant-publish-rights] assign the [`Pub/Sub Publisher`][publisher-role] role + to the service account in order to grant the Chat permission to publish user messages + to the defined topic. + +2. `spine-chat-bot-actor@.iam.gserviceaccount.com` — a custom service account we're + using as the credentials for the Chat API used by the bot. + + The Hangouts Chat API works only with dedicated service account keys and + [could not][chat-api-with-default-sa] be used with default credentials. The API itself does + not require any specific AIM role, but during the authentication the + [`chat.bot`][applying-chatbot-credentials] scope should be set. + 3. `-compute@developer.gserviceaccount.com` — default compute service account used by Cloud Run. -4. `@cloudbuild.gserviceaccount.com` — Cloud Build service account used by the - Cloud Build service to build and deploy the application. + + While we are relying on the default compute service account, virtually any service account + should work. In order to use the [Secret Manager](#secret-manager) API the service account + should have the secret `Secret Manager Viewer` role applied. + +4. `@cloudbuild.gserviceaccount.com` — [Cloud Build](#cloud-build) service account + used by the Cloud Build service to build and deploy the application. + + The Cloud Build service account is configured to act as a `Service Account User` and should + have the `Cloud Run Admin` role in order to be able to [deploy][cloud-build-deploy-cloud-run] + the application. + 5. `cloud-run-pubsub-invoker@.iam.gserviceaccount.com` — a custom service account we're - using to call the Cloud Run service from the Pub/Sub subscriptions. The Cloud Run - is not accepting unauthenticated calls by default and is not exposed to the internet. - -//TODO:2020-06-25:ysergiichuk: add roles/descriptions for service accounts - -[iam]: https://cloud.google.com/iam \ No newline at end of file + using to call the Cloud Run service from the [Pub/Sub](#pubsub) subscriptions. + + The Cloud Run is not accepting unauthenticated calls by default and is not exposed + to the internet. In order to be able to call the service, one + [must][cloud-run-service-to-service-auth] have the `Cloud Run Invoker` role. + +[iam]: https://cloud.google.com/iam +[grant-publish-rights]: https://developers.google.com/hangouts/chat/how-tos/pub-sub#grant_publish_rights_on_your_topic +[publisher-role]: https://cloud.google.com/pubsub/docs/access-control#roles +[chat-api-with-default-sa]: https://stackoverflow.com/questions/62571412/hangout-chat-api-authentication-fails-with-default-service-account +[applying-chatbot-credentials]: https://developers.google.com/hangouts/chat/how-tos/service-accounts#step_2_applying_credentials_to_http_request_headers +[cloud-build-deploy-cloud-run]: https://cloud.google.com/cloud-build/docs/deploying-builds/deploy-cloud-run +[cloud-run-service-to-service-auth]: https://cloud.google.com/run/docs/authenticating/service-to-service From f042ad20df737cacd63e1263d612969ccf2cca9e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 18:00:30 +0300 Subject: [PATCH 299/492] Add notes about the configured secrets --- ENVIRONMENT.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index ee1ed4af..e9668896 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -121,6 +121,17 @@ to [read][reading-secrets] the secrets, developers and service accounts should h `roles/secretmanager.viewer` role that is not available by default (see [IAM](#iam) section for details). +For the application we configure the following secrets: + +1. `ChatServiceAccount` — the private key of the chatbot actor that is used by the + [Hangouts Chat API](#hangouts-chat-api). + + The key is stored in JSON format as string value. + +2. `TravisApiToken` — the Travis CI API token. + + The API token is used to authenticate calls to the Travis CI v3 API. + [secret-manager]: https://cloud.google.com/secret-manager [managing-secrets]: https://cloud.google.com/secret-manager/docs/managing-secrets [reading-secrets]: https://cloud.google.com/secret-manager/docs/managing-secret-versions#get From d1cd267e2c54c8f8bb91b383140db64c084668ec Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 18:02:20 +0300 Subject: [PATCH 300/492] Add link to the new cloud environment document --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2e848aad..e66e675e 100644 --- a/README.md +++ b/README.md @@ -64,3 +64,8 @@ For detailed Application Default Credentials (ADC) guide for Docker see example Cloud Run [guide][cloud-run-local-guide]. [cloud-run-local-guide]: https://cloud.google.com/run/docs/testing/local#running_locally_using_docker_with_access_to_services + +## Running in the Cloud + +The application is deployed in the Google Cloud Platform cloud, and the overview of the +cloud deployment is available in a separate [document](ENVIRONMENT.md). From 300da05799cf74b9aefa096b3ecafb783b27ccda Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 22:24:54 +0300 Subject: [PATCH 301/492] Update Bootstrap to the latest v1.5.24 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c44aa090..c07f4329 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { implementation("net.ltgt.gradle:gradle-apt-plugin:0.21") implementation("com.github.jengelman.gradle.plugins:shadow:6.0.0") implementation("gradle.plugin.com.google.cloud.tools:jib-gradle-plugin:2.4.0") - implementation("io.spine.tools:spine-bootstrap:1.5.23") + implementation("io.spine.tools:spine-bootstrap:1.5.24") implementation("net.saliman:gradle-properties-plugin:1.5.1") } From e50168944a483c2c1d9e2ef196e84b33e35156c4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 25 Jun 2020 22:28:50 +0300 Subject: [PATCH 302/492] Use same notation for values. --- ENVIRONMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index e9668896..df4613d0 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -11,7 +11,7 @@ Cloud Run is a managed serverless solution that works with Docker images and cou the load when needed. In Cloud Run we configure a `chat-bot-server` service with the -`gcr.io//chat-bot-server` container image. The image is built automatically using +`gcr.io//chat-bot-server` container image. The image is built automatically using `jib` Gradle plugin and deployed to the [Container Registry][container-registry] for our needs as part of the build process. From f00943d17abf09b7358f4456df86893e120533de Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 15:59:04 +0300 Subject: [PATCH 303/492] Make Query abstract --- .idea/inspectionProfiles/Project_Default.xml | 30 ++++--------------- .../io/spine/chatbot/api/travis/Query.java | 2 +- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 03926c8c..4949f9cb 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java index e1d6a3e9..86f15ea6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java @@ -34,7 +34,7 @@ * @param * type of the expected query execution response */ -public class Query { +public abstract class Query { private final Class responseType; private final String request; From 3be0e70043689a530555ee3aedec28f4336e2bee Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 16:51:28 +0300 Subject: [PATCH 304/492] Replace BuildStates utility class with a mixin --- .../api/google/chat/BuildStateUpdates.java | 3 +- .../server/github/BuildStateMixin.java | 127 ++++++++++++++++++ .../chatbot/server/github/BuildStates.java | 83 ------------ .../server/github/RepoBuildProcess.java | 31 +---- .../chatbot/github/repository_build.proto | 2 + ...atesTest.java => BuildStateMixinTest.java} | 14 +- 6 files changed, 141 insertions(+), 119 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java delete mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{BuildStatesTest.java => BuildStateMixinTest.java} (79%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 97196d6c..383df33f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -29,7 +29,6 @@ import com.google.common.collect.ImmutableList; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.google.chat.thread.ThreadResource; -import io.spine.chatbot.server.github.BuildStates; import io.spine.protobuf.Messages; import static io.spine.chatbot.api.google.chat.ChatWidgets.cardWith; @@ -62,7 +61,7 @@ private BuildStateUpdates() { */ static Message buildStateMessage(BuildState buildState, ThreadResource thread) { checkValid(buildState); - var headerIcon = BuildStates.isFailed(buildState) ? FAILURE_ICON : SUCCESS_ICON; + var headerIcon = buildState.failed() ? FAILURE_ICON : SUCCESS_ICON; var cardHeader = new CardHeader() .setTitle(buildState.getRepositorySlug()) .setImageUrl(headerIcon); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java new file mode 100644 index 00000000..0a32192f --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -0,0 +1,127 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.BuildStateOrBuilder; +import io.spine.chatbot.github.repository.build.BuildStateStatusChange; + +import java.util.EnumSet; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.chatbot.github.repository.build.BuildState.State.PASSED; +import static io.spine.chatbot.github.repository.build.BuildState.State.S_UNKNOWN; +import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.FAILED; +import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; +import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; +import static io.spine.util.Exceptions.newIllegalArgumentException; +import static io.spine.util.Exceptions.newIllegalStateException; + +/** + * Augments {@link BuildState} with useful methods. + */ +@GeneratedMixin +public interface BuildStateMixin extends BuildStateOrBuilder { + + /** + * Determines whether the build is failed. + * + * @return `true` if the build is failed, `false` otherwise + * @see #failed(BuildState.State) + */ + default boolean failed() { + return failed(getState()); + } + + /** + * Creates an instance of the {@link BuildState.State build state} of out its + * string representation. + */ + static BuildState.State buildStateFrom(String state) { + checkNotNull(state); + for (BuildState.State buildState : BuildState.State.values()) { + if (state.equalsIgnoreCase(buildState.name())) { + return buildState; + } + } + throw newIllegalArgumentException( + "Unable to create build state out of the supplied string value `%s`.", state + ); + } + + /** + * Determines the {@link BuildStateStatusChange status chage} of the build comparing to the + * {@code previousState}. + * + * @see #stateStatusChangeOf(BuildStateMixin, BuildStateMixin) + */ + default BuildStateStatusChange stateChangeFrom(BuildStateMixin previousState) { + return stateStatusChangeOf(this, previousState); + } + + /** + * Determines the {@link BuildStateStatusChange status chage} between build states. + * + *

The status is considered: + * + *

    + *
  • {@code failed} if the new state is {@link #failed() failed}. + *
  • {@code recovered} if the new state is {@code passed} and the previous is + * {@link #failed() failed}. + *
  • {@code stable} if the new state is {@code passed} and the previous is either + * {@code unknown} meaning that there were no previous states or {@code passed} as well. + *
+ */ + private static BuildStateStatusChange stateStatusChangeOf(BuildStateMixin newBuildState, + BuildStateMixin previousBuildState) { + var currentState = newBuildState.getState(); + var previousState = previousBuildState.getState(); + if (newBuildState.failed()) { + return FAILED; + } + if (currentState == PASSED && previousBuildState.failed()) { + return RECOVERED; + } + if (currentState == PASSED && (previousState == PASSED || previousState == S_UNKNOWN)) { + return STABLE; + } + throw newIllegalStateException( + "Build is in an unpredictable state. Current state `%s`. Previous state `%s`.", + currentState.name(), previousState.name() + ); + } + + /** + * Determines whether the build state denotes a failed status. + * + *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered + * failed statuses. + * + * @return `true` if the build status is failed, `false` otherwise + */ + private static boolean failed(BuildState.State state) { + var failedStatuses = EnumSet.of( + BuildState.State.CANCELLED, BuildState.State.FAILED, BuildState.State.ERRORED + ); + return failedStatuses.contains(state); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java deleted file mode 100644 index b701cd7d..00000000 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStates.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.chatbot.server.github; - -import com.google.common.collect.ImmutableSet; -import io.spine.chatbot.github.repository.build.BuildState; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.util.Exceptions.newIllegalArgumentException; - -/** - * A utility class for working with {@link BuildState.State}s. - */ -public final class BuildStates { - - /** Failed Travis build states. **/ - private static final ImmutableSet FAILED_STATUSES = ImmutableSet.of( - BuildState.State.CANCELLED, BuildState.State.FAILED, BuildState.State.ERRORED - ); - - /** - * Prevents instantiation of this utility class. - */ - private BuildStates() { - } - - /** - * Creates an instance of the build state of out its string representation. - */ - static BuildState.State buildStateFrom(String state) { - checkNotNull(state); - for (BuildState.State buildState : BuildState.State.values()) { - if (state.equalsIgnoreCase(buildState.name())) { - return buildState; - } - } - throw newIllegalArgumentException( - "Unable to create build state out of the supplied string value `%s`.", state - ); - } - - /** - * Determines whether the build is failed. - * - * @return `true` if the build is failed, `false` otherwise - * @see #isFailed(BuildState.State) - */ - public static boolean isFailed(BuildState buildState) { - checkNotNull(buildState); - return isFailed(buildState.getState()); - } - - /** - * Determines whether the build state denotes a filed status. - * - *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered - * {@link #FAILED_STATUSES failed statuses}. - * - * @return `true` if the build status is failed, `false` otherwise - */ - public static boolean isFailed(BuildState.State state) { - checkNotNull(state); - return FAILED_STATUSES.contains(state); - } -} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index eb2daec6..35ac9adf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -30,7 +30,6 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.github.repository.build.BuildStateChange; -import io.spine.chatbot.github.repository.build.BuildStateStatusChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.chatbot.github.repository.build.event.BuildFailed; @@ -44,11 +43,6 @@ import io.spine.server.tuple.EitherOf3; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.github.repository.build.BuildState.State.PASSED; -import static io.spine.chatbot.github.repository.build.BuildState.State.S_UNKNOWN; -import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.FAILED; -import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; -import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; import static io.spine.net.Urls.travisBuildUrlFor; import static io.spine.protobuf.Messages.isDefault; import static io.spine.util.Exceptions.newIllegalStateException; @@ -112,7 +106,7 @@ EitherOf3 handle(CheckRepositoryBuild determineOutcome(RepositoryId repository, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); var previousBuildState = stateChange.getPreviousValue(); - var stateStatusChange = stateStatusChangeOf(newBuildState, previousBuildState); + var stateStatusChange = newBuildState.stateChangeFrom(previousBuildState); switch (stateStatusChange) { case FAILED: _info().log("Build for repository `%s` failed with status `%s`.", @@ -148,25 +142,6 @@ EitherOf3 handle(CheckRepositoryBuild } } - private static BuildStateStatusChange stateStatusChangeOf(BuildState newBuildState, - BuildState previousBuildState) { - var currentState = newBuildState.getState(); - var previousState = previousBuildState.getState(); - if (BuildStates.isFailed(currentState)) { - return FAILED; - } - if (currentState == PASSED && BuildStates.isFailed(previousState)) { - return RECOVERED; - } - if (currentState == PASSED && (previousState == PASSED || previousState == S_UNKNOWN)) { - return STABLE; - } - throw newIllegalStateException( - "Build is in an unpredictable state. Current state `%s`. Previous state `%s`.", - currentState.name(), previousState.name() - ); - } - @VisibleForTesting static BuildState buildStateFrom(RepoBranchBuildResponse branchBuild, String space) { var branchBuildName = branchBuild.getName(); @@ -177,8 +152,8 @@ static BuildState buildStateFrom(RepoBranchBuildResponse branchBuild, String spa .newBuilder() .setNumber(build.getNumber()) .setGoogleChatSpace(space) - .setState(BuildStates.buildStateFrom(build.getState())) - .setPreviousState(BuildStates.buildStateFrom(build.getPreviousState())) + .setState(BuildStateMixin.buildStateFrom(build.getState())) + .setPreviousState(BuildStateMixin.buildStateFrom(build.getPreviousState())) .setBranch(branchBuildName) .setLastCommit(from(build.getCommit())) .setCreatedBy(build.getCreatedBy() diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index fc46e682..7d36c739 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -75,6 +75,8 @@ enum BuildStateStatusChange { // State of the build for a repository branch. message BuildState { + option (is).java_type = "io.spine.chatbot.server.github.BuildStateMixin"; + // Incremental number for a repository's builds. string number = 1; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java similarity index 79% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java index c03dd57d..99137963 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStatesTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java @@ -20,18 +20,20 @@ package io.spine.chatbot.server.github; -import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.BuildStates.buildStateFrom; +import static io.spine.chatbot.server.github.BuildStateMixin.buildStateFrom; import static org.junit.jupiter.api.Assertions.assertThrows; -@DisplayName("BuildStates should") -final class BuildStatesTest extends UtilityClassTest { +@DisplayName("BuildStateMixin should") +final class BuildStateMixinTest { - BuildStatesTest() { - super(BuildStates.class); + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + @DisplayName("not accept `null` build states") + void notAcceptNull() { + assertThrows(NullPointerException.class, () -> buildStateFrom(null)); } @SuppressWarnings("ResultOfMethodCallIgnored") From 4c17b4a4dbf133be21c8e1c054cc4a2ff230a3e3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:08:45 +0300 Subject: [PATCH 305/492] Drop usage of personifications and fix comments. --- ENVIRONMENT.md | 111 +++++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index df4613d0..73b6fa70 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -6,17 +6,17 @@ this document provides an overview of the currently configured environment. ## Cloud Run -We use [Cloud Run][cloud-run] as our main compute platform for the ChatBot application. -Cloud Run is a managed serverless solution that works with Docker images and could scale -the load when needed. +The [Cloud Run][cloud-run] is used as the main compute platform for the ChatBot application. +Cloud Run is a managed serverless solution that works with Docker images and is able to scale +upon the load when needed. -In Cloud Run we configure a `chat-bot-server` service with the +The `chat-bot-server` service is configured in Cloud Run with the `gcr.io//chat-bot-server` container image. The image is built automatically using -`jib` Gradle plugin and deployed to the [Container Registry][container-registry] for our needs -as part of the build process. +[`jib`][jib] Gradle plugin and deployed to the [Container Registry][container-registry] as part +of the build process. Upon pushes to the `master` branch, the Cloud Build performs the automatic deployment of the -new Cloud Run revision. (see [Cloud Build](#cloud-build) section for details). +new Cloud Run revision (see [Cloud Build](#cloud-build) section for details). [cloud-run]: https://cloud.google.com/run [jib]: https://github.com/GoogleContainerTools/jib @@ -24,7 +24,7 @@ new Cloud Run revision. (see [Cloud Build](#cloud-build) section for details). ## Cloud Build -We use [Cloud Build] CI/CD solution to continuously build and deploy our application. +The [Cloud Build] CI/CD solution is used to continuously build and deploy the application. The Cloud Build configuration is available as [`cloudbuild.yaml`](./cloudbuild.yaml) and does the following: @@ -32,11 +32,11 @@ the following: 1. Starts the Gradle build for the project. 2. Deploys the new revision of the Cloud Run service. -In addition to the configuration, we create a Cloud Build trigger to automatically start build +In addition to the configuration, the Cloud Build trigger is configured to automatically start build and deploy process upon commits to the `master` branch. The Cloud Build itself uses GCP service accounts in order to access the APIs and should be -configured to allow the Cloud Run deployment. See the [IAM](#iam) section for details. +configured to allow the Cloud Run deployment (see the [IAM](#iam) section for details). [cloud-build]: https://cloud.google.com/cloud-build [cloud-build-trigger]: https://cloud.google.com/cloud-build/docs/automating-builds/create-manage-triggers#console @@ -46,13 +46,13 @@ configured to allow the Cloud Run deployment. See the [IAM](#iam) section for de The bot uses [Hangout Chat API][chat-api] and is linked to the GCP project. Currently, it's only possible to have a single bot per the GCP project. -The bot configuration could be done only via the web UI console as of the writing. It is published -in accordance to the publishing [guide][publishing-guide] where the essential configurations are: +The bot configuration is only available via the web UI console. The bot is published in accordance +to the publishing [guide][publishing-guide] where the essential configurations are: -1. `Functionality` — check `Bot works in rooms`. We do not expect the bot to work in direct messages. +1. `Functionality` — check `Bot works in rooms`. The bot is not expected to work in direct messages. 2. `Connection settings` — choose [`Cloud Pub/Sub`][pubsub-bot] and enter a Pub/Sub topic name - that'd be used to deliver messages from users to the bot. (for the Pub/Sub details see - [Pub/Sub](#pubsub) section) + that'd be used to deliver messages from users to the bot (for the Pub/Sub details see + [Pub/Sub](#pubsub) section). 3. `Permissions` — choose `Specific people and groups in your domain` and list individuals or groups in the domain who'd be able to install the bot. @@ -63,36 +63,38 @@ groups in the domain who'd be able to install the bot. ## Pub/Sub The application is built with resilience in mind and even though it exposes some REST APIs, -it is not intended to handle to load directly. Instead, we rely on the Google [Pub/Sub][pubsub] -async messaging service to receive the incoming messages and then stream the into the app. +it is not intended to handle to load directly. Instead, it relies on the Google [Pub/Sub][pubsub] +async messaging service to receive the incoming messages and then stream them into the app. -At the moment of writing, the app requires the following Pub/Sub topics to be configured: +The bot requires the following Pub/Sub topics to be configured: 1. `incoming-bot-messages` — that is the topic that is used in the `Connection settings` of the - bot configuration. The Hangouts Chat system takes care of propagating users messages to this + bot configuration. The Hangouts Chat system takes care of propagating user messages to this topic. - For the topic we configure the `incoming-bot-messages-cloud-run` push subscription that - delivers messages to the `/chat/incoming/event` endpoint of the Cloud Run [service](#cloud-run). - We configure The subscription with a backoff retry policy and the acknowledgement - deadline of 600 seconds. + For the topic the `incoming-bot-messages-cloud-run` push subscription is created with + a backoff retry policy and the acknowledgement deadline of 600 seconds. + The subscription delivers messages to the `/chat/incoming/event` endpoint of + the Cloud Run [service](#cloud-run). Also, the `dead lettering` is configured for the subscription, so all the undelivered - messages are sent to our next topic — `dead-incoming-bot-messages`. + messages are sent to `dead-incoming-bot-messages` topic. The subscription uses `cloud-run-pubsub-invoker` service account to implement service2service authentication (see [IAM](#iam) section for details). -2. `dead-incoming-bot-messages` — the topic that holds possible undelivered incoming messages. +2. `dead-incoming-bot-messages` — the topic that holds undelivered incoming messages. - For the topic we configure the `dead-incoming-bot-messages` pull never-expired subscription. - In case of an undelivered message, one could go and pull it from the subscription. + For the topic, the `dead-incoming-bot-messages` pull subscription that never expires + is configured. + In case of an undelivered message, one could go and pull it from the subscription. -3. `repository-checks` — the topic that delivers scheduled tasks to check the watched resources - build state (see [Cloud Scheduler](#cloud-scheduler) section for details) +3. `repository-checks` — the topic that delivers scheduled tasks to check the build state of + the watched resources (see [Cloud Scheduler](#cloud-scheduler) section for details). - For the topic we configure the `repository-checks-cloud-run` subscription that delivers messages - to the `/repositories/builds/check` endpoint of the Cloud Run [service](#cloud-run). + The `repository-checks-cloud-run` subscription is configured for the topic. The subscription + delivers messages to the `/repositories/builds/check` endpoint of the Cloud Run + [service](#cloud-run). The subscription uses the same `cloud-run-pubsub-invoker` service account as the `incoming-bot-messages-cloud-run` (see [IAM](#iam) section for details). @@ -100,28 +102,28 @@ At the moment of writing, the app requires the following Pub/Sub topics to be co ## Cloud Scheduler -For the CRON-based needs we rely on the [Cloud Scheduler][scheduler] service. +The [Cloud Scheduler][scheduler] service allows configuring multiple scheduled tasks that deliver +the payload to a particular target (HTTP endpoint, Pub/Sub topic or AppEngine endpoint). -The scheduler service allows to configure multiple scheduled tasks that can deliver the task -payload to a particular target (HTTP endpoint, Pub/Sub topic or AppEngine endpoint). - -For our needs, we configure a single CRON task `repositories-check-trigger` that emits -a Pub/Sub message with an empty payload to the `repository-checks` topic. We configure the task -to run every hour using the following unix-cron format expression: `0 * * * *`. +The CRON task `repositories-check-trigger` is configured for the bot. The task emits a Pub/Sub +message with an empty payload to the `repository-checks` topic. It is +[configured][configure-schedules] to run every hour using the following unix-cron format +expression: `0 * * * *`. [scheduler]: https://cloud.google.com/scheduler +[configure-schedules]: https://cloud.google.com/scheduler/docs/configuring/cron-job-schedules ## Secret Manager -To be able to use API tokens and service accounts securely in the application, -we use [Secret Manager][secret-manager] service that allows managing and rotate secrets with ease. +The [Secret Manager][secret-manager] service is used to supply application secrets like API tokens +and service accounts securely. -We [manage][managing-secrets] secrets using the Secret Manager Web UI, but in order to be able +The secreats are [managed][managing-secrets] the Secret Manager Web UI, but in order to be able to [read][reading-secrets] the secrets, developers and service accounts should have the -`roles/secretmanager.viewer` role that is not available by default (see [IAM](#iam) section +`roles/secretmanager.viewer` role that is not configured by default (see [IAM](#iam) section for details). -For the application we configure the following secrets: +The following secrets are configured for the bot: 1. `ChatServiceAccount` — the private key of the chatbot actor that is used by the [Hangouts Chat API](#hangouts-chat-api). @@ -138,33 +140,32 @@ For the application we configure the following secrets: ## IAM -Google [Cloud Identity and Access Management][iam] (IAM) lets us to fine-tune the authorization and -access management for the application. +The [Cloud Identity and Access Management][iam] (IAM) service is used to fine-tune the authorization +and access management for the application. -In order to run the application we configure the following service account and their respective -roles: +In order to run the application following service accounts, and their respective roles +are configured: 1. `chat-api-push@system.gserviceaccount.com` — a special Chat API service account used by the Chat to publish messages to the Pub/Sub topic. - We [must][grant-publish-rights] assign the [`Pub/Sub Publisher`][publisher-role] role + The [`Pub/Sub Publisher`][publisher-role] role [must][grant-publish-rights] be assigned to the service account in order to grant the Chat permission to publish user messages to the defined topic. -2. `spine-chat-bot-actor@.iam.gserviceaccount.com` — a custom service account we're - using as the credentials for the Chat API used by the bot. +2. `spine-chat-bot-actor@.iam.gserviceaccount.com` — a custom service account that is + used as the credentials for the Chat API. The Hangouts Chat API works only with dedicated service account keys and [could not][chat-api-with-default-sa] be used with default credentials. The API itself does not require any specific AIM role, but during the authentication the [`chat.bot`][applying-chatbot-credentials] scope should be set. -3. `-compute@developer.gserviceaccount.com` — default compute service account used by - Cloud Run. +3. `-compute@developer.gserviceaccount.com` — default service account used by Cloud Run. - While we are relying on the default compute service account, virtually any service account - should work. In order to use the [Secret Manager](#secret-manager) API the service account - should have the secret `Secret Manager Viewer` role applied. + It is not required to set a custom service account for the Cloud Run, but in order to use + the [Secret Manager](#secret-manager) API the service account should have the + `Secret Manager Viewer` role applied. 4. `@cloudbuild.gserviceaccount.com` — [Cloud Build](#cloud-build) service account used by the Cloud Build service to build and deploy the application. From ae3d4608c3074dfb290bc21c8d6351ce20a0a5b4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:15:19 +0300 Subject: [PATCH 306/492] Add note about configuring Cloud Build for GitHub --- ENVIRONMENT.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 73b6fa70..e37ed793 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -33,13 +33,17 @@ the following: 2. Deploys the new revision of the Cloud Run service. In addition to the configuration, the Cloud Build trigger is configured to automatically start build -and deploy process upon commits to the `master` branch. +and deploy process upon commits to the `master` branch. In order to allow Cloud Build to +fetch code from the GitHub, the Cloud Build GitHub [application][cloud-build-github-app] +is [configured][run-builds-on-github] for the organization. The Cloud Build itself uses GCP service accounts in order to access the APIs and should be configured to allow the Cloud Run deployment (see the [IAM](#iam) section for details). [cloud-build]: https://cloud.google.com/cloud-build [cloud-build-trigger]: https://cloud.google.com/cloud-build/docs/automating-builds/create-manage-triggers#console +[cloud-build-github-app]: https://github.com/marketplace/google-cloud-build +[run-builds-on-github]: https://cloud.google.com/cloud-build/docs/automating-builds/run-builds-on-github ## Hangouts Chat API From ccd80e1d50b91ef99b59ba5794d51ad5d7023d0f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:16:39 +0300 Subject: [PATCH 307/492] Add missing link --- ENVIRONMENT.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index e37ed793..2e8424c3 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -24,7 +24,8 @@ new Cloud Run revision (see [Cloud Build](#cloud-build) section for details). ## Cloud Build -The [Cloud Build] CI/CD solution is used to continuously build and deploy the application. +The [Cloud Build][cloud-build] CI/CD solution is used to continuously build and deploy +the application. The Cloud Build configuration is available as [`cloudbuild.yaml`](./cloudbuild.yaml) and does the following: From c007a83210e992686fd06150cb7151efc14baedb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:17:34 +0300 Subject: [PATCH 308/492] fix articl --- ENVIRONMENT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 2e8424c3..d6334b9f 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -30,8 +30,8 @@ the application. The Cloud Build configuration is available as [`cloudbuild.yaml`](./cloudbuild.yaml) and does the following: -1. Starts the Gradle build for the project. -2. Deploys the new revision of the Cloud Run service. +1. Starts Gradle build for the project. +2. Deploys a new revision of the Cloud Run service. In addition to the configuration, the Cloud Build trigger is configured to automatically start build and deploy process upon commits to the `master` branch. In order to allow Cloud Build to From 4187134c9605fef7aeadcfc896c6673026c380a8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:18:44 +0300 Subject: [PATCH 309/492] drop currently piece --- ENVIRONMENT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index d6334b9f..7b02e8ae 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -48,8 +48,8 @@ configured to allow the Cloud Run deployment (see the [IAM](#iam) section for de ## Hangouts Chat API -The bot uses [Hangout Chat API][chat-api] and is linked to the GCP project. Currently, it's only -possible to have a single bot per the GCP project. +The bot uses [Hangout Chat API][chat-api] and is linked to the GCP project. It is only possible +to have a single bot per the GCP project. The bot configuration is only available via the web UI console. The bot is published in accordance to the publishing [guide][publishing-guide] where the essential configurations are: From 9fb9f5e82ae269e4a8a72d94fdebd07d714a72fd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:25:52 +0300 Subject: [PATCH 310/492] Cleanup wording --- ENVIRONMENT.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 7b02e8ae..6bea9a77 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -54,12 +54,13 @@ to have a single bot per the GCP project. The bot configuration is only available via the web UI console. The bot is published in accordance to the publishing [guide][publishing-guide] where the essential configurations are: -1. `Functionality` — check `Bot works in rooms`. The bot is not expected to work in direct messages. -2. `Connection settings` — choose [`Cloud Pub/Sub`][pubsub-bot] and enter a Pub/Sub topic name - that'd be used to deliver messages from users to the bot (for the Pub/Sub details see - [Pub/Sub](#pubsub) section). -3. `Permissions` — choose `Specific people and groups in your domain` and list individuals or -groups in the domain who'd be able to install the bot. +1. `Functionality` — `Bot works in rooms` is checked. The bot is not expected to work + in direct messages. +2. `Connection settings` — [`Cloud Pub/Sub`][pubsub-bot] is choosen and a Pub/Sub topic name + that is used to deliver messages from users to the bot is configured (for the Pub/Sub details + see [Pub/Sub](#pubsub) section). +3. `Permissions` — a list of individuals in the domain who are able to install the bot + is configured in the `Specific people and groups in your domain` field. [chat-api]: https://developers.google.com/hangouts/chat [publishing-guide]: https://developers.google.com/hangouts/chat/how-tos/bots-publish @@ -73,7 +74,7 @@ async messaging service to receive the incoming messages and then stream them in The bot requires the following Pub/Sub topics to be configured: -1. `incoming-bot-messages` — that is the topic that is used in the `Connection settings` of the +1. `incoming-bot-messages` — the topic that is used in the `Connection settings` of the bot configuration. The Hangouts Chat system takes care of propagating user messages to this topic. @@ -83,7 +84,7 @@ The bot requires the following Pub/Sub topics to be configured: the Cloud Run [service](#cloud-run). Also, the `dead lettering` is configured for the subscription, so all the undelivered - messages are sent to `dead-incoming-bot-messages` topic. + messages are sent to the `dead-incoming-bot-messages` topic. The subscription uses `cloud-run-pubsub-invoker` service account to implement service2service authentication (see [IAM](#iam) section for details). @@ -92,7 +93,7 @@ The bot requires the following Pub/Sub topics to be configured: For the topic, the `dead-incoming-bot-messages` pull subscription that never expires is configured. - In case of an undelivered message, one could go and pull it from the subscription. + In case of an undelivered message, it could be pulled from the subscription. 3. `repository-checks` — the topic that delivers scheduled tasks to check the build state of the watched resources (see [Cloud Scheduler](#cloud-scheduler) section for details). @@ -111,7 +112,7 @@ The [Cloud Scheduler][scheduler] service allows configuring multiple scheduled t the payload to a particular target (HTTP endpoint, Pub/Sub topic or AppEngine endpoint). The CRON task `repositories-check-trigger` is configured for the bot. The task emits a Pub/Sub -message with an empty payload to the `repository-checks` topic. It is +message with an empty payload to the `repository-checks` topic and is [configured][configure-schedules] to run every hour using the following unix-cron format expression: `0 * * * *`. @@ -123,7 +124,7 @@ expression: `0 * * * *`. The [Secret Manager][secret-manager] service is used to supply application secrets like API tokens and service accounts securely. -The secreats are [managed][managing-secrets] the Secret Manager Web UI, but in order to be able +The secrets are [managed][managing-secrets] in the Secret Manager Web UI, but in order to be able to [read][reading-secrets] the secrets, developers and service accounts should have the `roles/secretmanager.viewer` role that is not configured by default (see [IAM](#iam) section for details). @@ -148,7 +149,7 @@ The following secrets are configured for the bot: The [Cloud Identity and Access Management][iam] (IAM) service is used to fine-tune the authorization and access management for the application. -In order to run the application following service accounts, and their respective roles +In order to run the application, the following service accounts, and their respective roles are configured: 1. `chat-api-push@system.gserviceaccount.com` — a special Chat API service account used by the @@ -179,11 +180,11 @@ are configured: have the `Cloud Run Admin` role in order to be able to [deploy][cloud-build-deploy-cloud-run] the application. -5. `cloud-run-pubsub-invoker@.iam.gserviceaccount.com` — a custom service account we're - using to call the Cloud Run service from the [Pub/Sub](#pubsub) subscriptions. +5. `cloud-run-pubsub-invoker@.iam.gserviceaccount.com` — a custom service account + used to call the Cloud Run service from the [Pub/Sub](#pubsub) subscriptions. The Cloud Run is not accepting unauthenticated calls by default and is not exposed - to the internet. In order to be able to call the service, one + to the internet. In order to be able to call the service, the caller [must][cloud-run-service-to-service-auth] have the `Cloud Run Invoker` role. [iam]: https://cloud.google.com/iam From d31c3eceda1c40790862c1101624c5618deb799f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:27:36 +0300 Subject: [PATCH 311/492] Drop extra article --- ENVIRONMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 6bea9a77..bc8e4788 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -49,7 +49,7 @@ configured to allow the Cloud Run deployment (see the [IAM](#iam) section for de ## Hangouts Chat API The bot uses [Hangout Chat API][chat-api] and is linked to the GCP project. It is only possible -to have a single bot per the GCP project. +to have a single bot per GCP project. The bot configuration is only available via the web UI console. The bot is published in accordance to the publishing [guide][publishing-guide] where the essential configurations are: From ad92328b63a34b04ffd42e560964596a908327ec Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 19:30:48 +0300 Subject: [PATCH 312/492] Add link to push/pull Pub/Sub subscriptions --- ENVIRONMENT.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index bc8e4788..c59722d2 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -78,8 +78,8 @@ The bot requires the following Pub/Sub topics to be configured: bot configuration. The Hangouts Chat system takes care of propagating user messages to this topic. - For the topic the `incoming-bot-messages-cloud-run` push subscription is created with - a backoff retry policy and the acknowledgement deadline of 600 seconds. + For the topic the `incoming-bot-messages-cloud-run` [push subscription][push-subscription] + is created with a backoff retry policy and the acknowledgement deadline of 600 seconds. The subscription delivers messages to the `/chat/incoming/event` endpoint of the Cloud Run [service](#cloud-run). @@ -91,8 +91,8 @@ The bot requires the following Pub/Sub topics to be configured: 2. `dead-incoming-bot-messages` — the topic that holds undelivered incoming messages. - For the topic, the `dead-incoming-bot-messages` pull subscription that never expires - is configured. + For the topic, the `dead-incoming-bot-messages` [pull subscription][pull-subscription] + that never expires is configured. In case of an undelivered message, it could be pulled from the subscription. 3. `repository-checks` — the topic that delivers scheduled tasks to check the build state of @@ -105,6 +105,8 @@ The bot requires the following Pub/Sub topics to be configured: `incoming-bot-messages-cloud-run` (see [IAM](#iam) section for details). [pubsub]: https://cloud.google.com/pubsub +[push-subscription]: https://cloud.google.com/pubsub/docs/push +[pull-subscription]: https://cloud.google.com/pubsub/docs/pull ## Cloud Scheduler From 972e5c905ce4c01eae6ad8ee10bfe4fac15dfd90 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 20:02:26 +0300 Subject: [PATCH 313/492] Cleanup Application methods and move to using Logging interface. --- .idea/misc.xml | 17 +++--- .../java/io/spine/chatbot/Application.java | 53 +++++++++++++------ .../chatbot/IncomingEventsControllerTest.java | 5 +- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 1b21f7c1..425e8bb6 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,13 +1,14 @@ - - - - - - - + + + + + + + + @@ -61,4 +62,4 @@ - + \ No newline at end of file diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 85950be6..2893ffb0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -21,12 +21,15 @@ package io.spine.chatbot; import com.google.common.annotations.VisibleForTesting; -import com.google.common.flogger.FluentLogger; +import com.google.errorprone.annotations.concurrent.LazyInit; +import io.micronaut.context.event.ShutdownEvent; import io.micronaut.runtime.Micronaut; +import io.micronaut.runtime.event.annotation.EventListener; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.logging.Logging; import io.spine.server.Server; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import java.io.IOException; @@ -45,7 +48,7 @@ * @see IncomingEventsController * @see RepositoriesController **/ -public final class Application { +public final class Application implements Logging { static { System.setProperty( @@ -54,11 +57,12 @@ public final class Application { ); } - private static final FluentLogger LOGGER = Logging.loggerFor(Application.class); - /** Name of the GRPC {@link Server}. **/ static final String SERVER_NAME = "ChatBotServer"; + @LazyInit + private @MonotonicNonNull Server server; + /** * Prevents direct instantiation. */ @@ -72,35 +76,49 @@ private Application() { * the {@link Micronaut}. */ public static void main(String[] args) { - LOGGER.atFine() - .log("Starting Spine ChatBot application."); - initializeSpine(); - Micronaut.run(Application.class, args); + var application = new Application(); + application.start(args); } /** - * Initializes Spine server environment and starts Spine {@link Server}. + * Starts the application. + * + *

Performs bounded contexts initialization, starts GRPC {@link Server} and runs + * the {@link Micronaut}. */ - private static void initializeSpine() { - LOGGER.atConfig() - .log("Initializing server environment."); + private void start(String[] args) { + _config().log("Initializing server environment."); ChatBotServerEnvironment.init(); + _config().log("Setting up bounded contexts."); var gitHubContext = GitHubContext .newBuilder() .build(); var googleChatContext = GoogleChatContext .newBuilder() .build(); - startSpineServer(gitHubContext, googleChatContext); + _config().log("Starting GRPC server."); + server = startServer(gitHubContext, googleChatContext); + _config().log("Starting Micronaut application."); + Micronaut.run(Application.class, args); + } + + /** + * Gracefully stops the {@link #server}. + */ + @SuppressWarnings("TestOnlyProblems") // we do want to be sure that the GRPC server is shut down + @EventListener + void on(ShutdownEvent event) { + _info().log("Shutting down the application."); + if (server != null) { + server.shutdownAndWait(); + } } /** - * Starts Spine in-process server. + * Starts in-process GRPC server. */ @VisibleForTesting - static void startSpineServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { - LOGGER.atConfig() - .log("Starting server."); + static Server startServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { Server server = Server .inProcess(SERVER_NAME) .add(gitHubContext.contextBuilder()) @@ -113,5 +131,6 @@ static void startSpineServer(GitHubContext gitHubContext, GoogleChatContext goog e, "Unable to start Spine GRPC server `%s`.", SERVER_NAME ); } + return server; } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 5049681e..ea3bc817 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -40,7 +40,7 @@ import javax.inject.Inject; import static io.micronaut.http.HttpRequest.POST; -import static io.spine.chatbot.Application.startSpineServer; +import static io.spine.chatbot.Application.startServer; import static org.junit.jupiter.api.Assertions.assertEquals; @DisplayName("IncomingEventsController should") @@ -54,6 +54,7 @@ final class IncomingEventsControllerTest { @Client("/") HttpClient client; + @SuppressWarnings("ResultOfMethodCallIgnored") // we're not interested in GRPC server here @BeforeAll static void setupServer() { var chatContext = GoogleChatContext @@ -64,7 +65,7 @@ static void setupServer() { .newBuilder() .setTravis(InMemoryTravisClient.lenientClient()) .build(); - startSpineServer(gitHubContext, chatContext); + startServer(gitHubContext, chatContext); } @Test From 05e8309ddd9610c2d31f3decf26a2a38c79e603f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Fri, 26 Jun 2020 20:03:45 +0300 Subject: [PATCH 314/492] Use Micronaut release version --- buildSrc/src/main/kotlin/deps.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index dd45ef72..bcceae7b 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -28,7 +28,7 @@ object Versions { const val flogger = "0.5.1" const val junit5 = "5.6.2" const val truth = "1.0.1" - const val micronaut = "2.0.0.RC2" + const val micronaut = "2.0.0" const val spineGcloud = "1.5.22" const val googleSecretManager = "1.1.0" const val googleChat = "v1-rev20200617-1.30.9" From 10cbcc93a0c04690ed4aaacb0bc4ed64f8340467 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 06:53:25 +0300 Subject: [PATCH 315/492] bump bot version --- version.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle.kts b/version.gradle.kts index 5073bd1b..36920ab2 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -22,4 +22,4 @@ * The version of the application. */ -val botVersion: String by extra("0.0.1") +val botVersion: String by extra("0.9.0") From 34319ecb5a604f5ae17fd85ecb990d95cd5326eb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 06:54:00 +0300 Subject: [PATCH 316/492] drop copyright from Gradle wrapper props --- gradle/wrapper/gradle-wrapper.properties | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f7ecde68..7c0e0d60 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,23 +1,3 @@ -# -# Copyright 2020, TeamDev. All rights reserved. -# -# Redistribution and use in source and/or binary forms, with or without -# modification, must retain the above copyright notice and the following -# disclaimer. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - #Mon Jun 15 15:39:45 EEST 2020 distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip distributionBase=GRADLE_USER_HOME From ed2657192ac6099477d80df8de1dca12758e1205 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 06:55:05 +0300 Subject: [PATCH 317/492] Use static imports --- .../chatbot/server/google/chat/SpaceAggregateTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 577403cc..75761564 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -25,8 +25,6 @@ import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.google.chat.incoming.ChatEvent; -import io.spine.chatbot.google.chat.incoming.EventType; -import io.spine.chatbot.google.chat.incoming.SpaceType; import io.spine.chatbot.google.chat.incoming.User; import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import org.junit.jupiter.api.BeforeEach; @@ -34,6 +32,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.google.chat.incoming.EventType.ADDED_TO_SPACE; +import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @DisplayName("SpaceAggregate should") @@ -94,7 +94,7 @@ void setUp() { .setSpace(chatSpace()) .setUser(User.newBuilder() .setName("users/12e1ojep1")) - .setType(EventType.ADDED_TO_SPACE) + .setType(ADDED_TO_SPACE) .setEventTime("2020-06-19T15:39:01Z") .vBuild(); var botAddedToSpace = BotAddedToSpace @@ -135,7 +135,7 @@ private io.spine.chatbot.google.chat.incoming.Space chatSpace() { .newBuilder() .setName(SPACE.getValue()) .setDisplayName(DISPLAY_NAME) - .setType(SpaceType.ROOM) + .setType(ROOM) .vBuild(); } } From 22c6c5265afd2071b2564da3a6273761de576b18 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 06:57:18 +0300 Subject: [PATCH 318/492] Use static imports and reformat code --- .../google/chat/GoogleChatIdentifierTest.java | 24 ++++++++++++------- .../chat/IncomingEventsHandlerTest.java | 9 ++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java index ade3cdfc..7f24ca3c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java @@ -24,7 +24,6 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.testing.UtilityClassTest; import io.spine.validate.ValidationException; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -37,6 +36,7 @@ import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; @DisplayName("GoogleChatIdentifier should") @@ -57,14 +57,14 @@ final class NotAcceptInvalid { @MethodSource("spaceIdsSource") @DisplayName("space IDs") void spaceIds(String value) { - Assertions.assertThrows(ValidationException.class, () -> space(value)); + assertThrows(ValidationException.class, () -> space(value)); } @ParameterizedTest @MethodSource("messageIdsSource") @DisplayName("space IDs") void messageIds(String value) { - Assertions.assertThrows(ValidationException.class, () -> message(value)); + assertThrows(ValidationException.class, () -> message(value)); } @SuppressWarnings("unused") // method is used as parameterized test source @@ -82,17 +82,23 @@ private Stream messageIdsSource() { @DisplayName("create space ID") void createSpaceId() { var spaceId = "spaces/qew21466"; - assertThat(space(spaceId)).isEqualTo(SpaceId.newBuilder() - .setValue(spaceId) - .buildPartial()); + var expectedSpace = SpaceId + .newBuilder() + .setValue(spaceId) + .buildPartial(); + assertThat(space(spaceId)) + .isEqualTo(expectedSpace); } @Test @DisplayName("create message ID") void createMessageId() { var messageId = "spaces/qew21466/messages/123112111"; - assertThat(message(messageId)).isEqualTo(MessageId.newBuilder() - .setValue(messageId) - .buildPartial()); + var expectedMessage = MessageId + .newBuilder() + .setValue(messageId) + .buildPartial(); + assertThat(message(messageId)) + .isEqualTo(expectedMessage); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index 717ba9b7..c68387b1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -33,6 +33,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.google.chat.incoming.EventType.ADDED_TO_SPACE; +import static io.spine.chatbot.google.chat.incoming.EventType.MESSAGE; +import static io.spine.chatbot.google.chat.incoming.EventType.REMOVED_FROM_SPACE; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @@ -46,7 +49,7 @@ final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { @DisplayName("add bot to a space") void addBot() { // given - var chatEvent = chatEventOfType(EventType.ADDED_TO_SPACE); + var chatEvent = chatEventOfType(ADDED_TO_SPACE); var botAddedToSpace = BotAddedToSpace .newBuilder() .setEvent(chatEvent) @@ -62,7 +65,7 @@ void addBot() { @DisplayName("remove bot from the space") void removeBot() { // given - var chatEvent = chatEventOfType(EventType.REMOVED_FROM_SPACE); + var chatEvent = chatEventOfType(REMOVED_FROM_SPACE); var botRemovedFromSpace = BotRemovedFromSpace .newBuilder() .setEvent(chatEvent) @@ -78,7 +81,7 @@ void removeBot() { @DisplayName("receive incoming message") void receiveIncomingMessage() { // given - var chatEvent = chatEventOfType(EventType.MESSAGE); + var chatEvent = chatEventOfType(MESSAGE); var messageReceived = MessageReceived .newBuilder() .setEvent(chatEvent) From 0edf4f3387040db9eda7e35f71d1e2514bbd65d1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 06:59:06 +0300 Subject: [PATCH 319/492] Make abstract classes abstract --- .../src/test/java/io/spine/chatbot/api/FailFastClient.java | 2 +- .../io/spine/chatbot/server/github/GitHubContextAwareTest.java | 2 +- .../chatbot/server/google/chat/GoogleChatContextAwareTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java index 7f91a094..5978a720 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java @@ -29,7 +29,7 @@ /** * An abstract API client that exposes the {@code fail-fast} concept to the actual test clients. */ -public class FailFastClient implements Logging { +public abstract class FailFastClient implements Logging { /** Determines whether the client should fail if a particular response is not preconfigured. **/ private final boolean failFast; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java index 64a6d57e..8daba455 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java @@ -29,7 +29,7 @@ /** * An abstract test-base for GitHub context-based tests. */ -class GitHubContextAwareTest extends ContextAwareTest { +abstract class GitHubContextAwareTest extends ContextAwareTest { private final InMemoryTravisClient travisClient = InMemoryTravisClient.strictClient(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java index 60eab080..642493ad 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java @@ -29,7 +29,7 @@ /** * An abstract test-base for Google Chat context-based tests. */ -class GoogleChatContextAwareTest extends ContextAwareTest { +abstract class GoogleChatContextAwareTest extends ContextAwareTest { private final InMemoryGoogleChatClient googleChatClient = InMemoryGoogleChatClient.strictClient(); From 8313ed8819c5bc91d56ac8e47382ccb81ab21777 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:05:39 +0300 Subject: [PATCH 320/492] use meaningful setup methods --- .../chatbot/server/github/OrganizationAggregateTest.java | 2 +- .../spine/chatbot/server/github/RepoBuildProcessTest.java | 6 +++--- .../chatbot/server/github/RepositoryAggregateTest.java | 2 +- .../chatbot/server/github/SpineOrgInitProcessTest.java | 6 +++--- .../chatbot/server/google/chat/SpaceAggregateTest.java | 2 +- .../chatbot/server/google/chat/ThreadAggregateTest.java | 2 +- .../chatbot/server/google/chat/ThreadChatProcessTest.java | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 8e6b3898..d72ab482 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -52,7 +52,7 @@ final class Register { private final Url websiteUrl = urlOfSpec("https://test-organization.com"); @BeforeEach - void setUp() { + void registerOrganization() { var registerOrganization = RegisterOrganization .newBuilder() .setId(organization) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index fe15e197..492f01f0 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -80,7 +80,7 @@ final class FailedBuild { private final BuildState buildState = buildStateFrom(branchBuild, chatSpace); @BeforeEach - void setUp() { + void sendCheckCommand() { travisClient().setBuildsFor(repository.getValue(), branchBuild); var checkRepoBuild = CheckRepositoryBuild .newBuilder() @@ -135,7 +135,7 @@ final class RecoveredBuild { private final BuildState newBuildState = buildStateFrom(newBranchBuild, chatSpace); @BeforeEach - void setUp() { + void sendCheckCommands() { travisClient().setBuildsFor(repository.getValue(), previousBranchBuild); var checkRepoFailure = CheckRepositoryBuild .newBuilder() @@ -201,7 +201,7 @@ final class StableBuild { private final BuildState newBuildState = buildStateFrom(newBranchBuild, chatSpace); @BeforeEach - void setUp() { + void sendCheckCommands() { travisClient().setBuildsFor(repository.getValue(), branchBuildOf(initialFailedBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index a8a1ae0f..2605364a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -54,7 +54,7 @@ final class Register { private final Url travisCiUrl = travisUrlFor(REPO_SLUG); @BeforeEach - void setUp() { + void registerRepository() { var registerRepository = RegisterRepository .newBuilder() .setRepository(repository) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 1deb883c..d3cc4d8c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -25,13 +25,13 @@ import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; -import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.SpineOrgInitProcess.SPINE_ORGANIZATION; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @DisplayName("SpineOrgInitProcess should") final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @@ -40,7 +40,7 @@ final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @DisplayName("perform initialization of watched spine resources") final class Init { - private final SpaceId spaceId = GoogleChatIdentifier.space("spaces/qjwrp1441"); + private final SpaceId spaceId = space("spaces/qjwrp1441"); private final Repository repository = Repository .newBuilder() .setId(123312L) @@ -49,7 +49,7 @@ final class Init { .vBuild(); @BeforeEach - void setUp() { + void registerSpace() { var repositoriesResponse = RepositoriesResponse .newBuilder() .addRepositories(repository) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 75761564..58fd7697 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -47,7 +47,7 @@ final class SpaceAggregateTest extends GoogleChatContextAwareTest { final class Register { @BeforeEach - void setUp() { + void registerSpace() { var registerSpace = RegisterSpace .newBuilder() .setId(SPACE) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 20f461ad..0a042304 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -52,7 +52,7 @@ final class InitThread { threadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); @BeforeEach - void setUp() { + void createThread() { var threadCreated = ThreadCreated .newBuilder() .setThread(thread) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 8eb077e5..b87e0fb2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -94,7 +94,7 @@ private abstract static class BuildStateChanged extends GoogleChatContextAwareTe .setThread(newThread); @BeforeEach - void setUp() { + void receiveBuildStateChange() { googleChatClient().setMessageForBuildStatusUpdate(buildNumber, sentMessage); var newBuildState = BuildState .newBuilder() From d9a2d809162a41143da35f672b1d99623d59093a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:08:18 +0300 Subject: [PATCH 321/492] Rename to FailFastAwareClient --- .../api/{FailFastClient.java => FailFastAwareClient.java} | 4 ++-- .../chatbot/api/google/chat/InMemoryGoogleChatClient.java | 4 ++-- .../io/spine/chatbot/api/travis/InMemoryTravisClient.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename google-chat-bot/src/test/java/io/spine/chatbot/api/{FailFastClient.java => FailFastAwareClient.java} (96%) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastAwareClient.java similarity index 96% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastAwareClient.java index 5978a720..2ab9c4b7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastAwareClient.java @@ -29,7 +29,7 @@ /** * An abstract API client that exposes the {@code fail-fast} concept to the actual test clients. */ -public abstract class FailFastClient implements Logging { +public abstract class FailFastAwareClient implements Logging { /** Determines whether the client should fail if a particular response is not preconfigured. **/ private final boolean failFast; @@ -37,7 +37,7 @@ public abstract class FailFastClient implements Logging { /** * Creates a new client with the specified {@code failFast} behavior. */ - protected FailFastClient(boolean failFast) { + protected FailFastAwareClient(boolean failFast) { this.failFast = failFast; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java index 8a15dbd4..c6edae0b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java @@ -21,7 +21,7 @@ package io.spine.chatbot.api.google.chat; import com.google.api.services.chat.v1.model.Message; -import io.spine.chatbot.api.FailFastClient; +import io.spine.chatbot.api.FailFastAwareClient; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.google.chat.thread.ThreadResource; @@ -33,7 +33,7 @@ /** * An in-memory test-only implementation of the Google Chat client. */ -public final class InMemoryGoogleChatClient extends FailFastClient implements GoogleChatClient { +public final class InMemoryGoogleChatClient extends FailFastAwareClient implements GoogleChatClient { private final Map sentMessages = new ConcurrentHashMap<>(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java index 5461b142..677ccd16 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java @@ -20,7 +20,7 @@ package io.spine.chatbot.api.travis; -import io.spine.chatbot.api.FailFastClient; +import io.spine.chatbot.api.FailFastAwareClient; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -31,7 +31,7 @@ /** * An in-memory test-only implementation of the Travis CI API client. */ -public final class InMemoryTravisClient extends FailFastClient implements TravisClient { +public final class InMemoryTravisClient extends FailFastAwareClient implements TravisClient { private final Map, TravisResponse> responses = new ConcurrentHashMap<>(); From 6ed3e2cda4a8225216b0061fdb1db29151c96fe1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:11:08 +0300 Subject: [PATCH 322/492] Add steps docs --- cloudbuild.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 044a50cf..0da28f53 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,7 +1,12 @@ steps: + # The following step starts the build process using Gradle official image, performs the build + # and runs `jib` for the specified `gcpProject` in order to build and deploy the container + # image to the Google Container Registry. - name: 'gradle:6.4.1-jdk11' entrypoint: 'gradle' args: [ 'build', 'jib', '-PgcpProject=${PROJECT_ID}' ] + # The following step deploys the previously produced container image to the Cloud Run environment + # with the pre-configured `GCP_PROJECT_ID` environment variable. - name: 'google/cloud-sdk:slim' entrypoint: 'gcloud' args: [ From 38ef034954ae2fdcc56f63e363301573ddc049ea Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:12:10 +0300 Subject: [PATCH 323/492] Cleanup doc --- .../src/main/java/io/spine/chatbot/BeanFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 594ba7ae..7717e146 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -50,7 +50,8 @@ PubsubPushNotificationDeserializer pubsubDeserializer() { } /** - * Spine-based {@link PubsubPushRequest} Jackson deserializer. + * Deserializes JSON arriving with {@link PubsubPushRequest} into Spine-compatible + * data structures. * * @see * Jackson Deserialization From 7db553eb50202899bc5ee4125c33ac14cf481c36 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:13:33 +0300 Subject: [PATCH 324/492] Use chained calls and inline storage factory --- .../io/spine/chatbot/ChatBotServerEnvironment.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java index 16bf11b2..d72f1a93 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java @@ -54,16 +54,16 @@ private ChatBotServerEnvironment() { * Initializes {@link ServerEnvironment} for ChatBot. */ static void init() { - var se = ServerEnvironment.instance(); - var storageFactory = dsStorageFactory(); - se.use(InMemoryTransportFactory.newInstance(), Production.class); //TODO:2020-06-21:yuri-sergiichuk: switch to io.spine.chatbot.delivery.DistributedDelivery // for Production environment after implementing the delivery strategy. // see https://github.com/SpineEventEngine/chat-bot/issues/5. - se.use(LocalDelivery.instance, Production.class); - se.use(LocalDelivery.instance, Tests.class); - se.use(storageFactory, Production.class); - se.use(InMemoryStorageFactory.newInstance(), Tests.class); + ServerEnvironment + .instance() + .use(InMemoryTransportFactory.newInstance(), Production.class) + .use(LocalDelivery.instance, Production.class) + .use(LocalDelivery.instance, Tests.class) + .use(dsStorageFactory(), Production.class) + .use(InMemoryStorageFactory.newInstance(), Tests.class); } private static DatastoreStorageFactory dsStorageFactory() { From 312bca701314ab133411e8fafb5e515446a2e5f8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:22:40 +0300 Subject: [PATCH 325/492] Register onShutdown listener directly --- .../java/io/spine/chatbot/Application.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 2893ffb0..2e45d603 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -22,9 +22,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.concurrent.LazyInit; +import io.micronaut.context.event.ApplicationEventListener; import io.micronaut.context.event.ShutdownEvent; import io.micronaut.runtime.Micronaut; -import io.micronaut.runtime.event.annotation.EventListener; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.logging.Logging; @@ -33,6 +33,7 @@ import java.io.IOException; +import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.util.Exceptions.newIllegalStateException; /** @@ -99,19 +100,8 @@ private void start(String[] args) { _config().log("Starting GRPC server."); server = startServer(gitHubContext, googleChatContext); _config().log("Starting Micronaut application."); - Micronaut.run(Application.class, args); - } - - /** - * Gracefully stops the {@link #server}. - */ - @SuppressWarnings("TestOnlyProblems") // we do want to be sure that the GRPC server is shut down - @EventListener - void on(ShutdownEvent event) { - _info().log("Shutting down the application."); - if (server != null) { - server.shutdownAndWait(); - } + var applicationContext = Micronaut.run(Application.class, args); + applicationContext.registerSingleton(new Stopper(server)); } /** @@ -133,4 +123,24 @@ static Server startServer(GitHubContext gitHubContext, GoogleChatContext googleC } return server; } + + /** + * Gracefully stops the {@link #server}. + */ + private static final class Stopper implements ApplicationEventListener, Logging { + + private final Server server; + + private Stopper(Server server) { + this.server = checkNotNull(server); + } + + @Override + public void onApplicationEvent(ShutdownEvent event) { + _info().log("Shutting down the application."); + if (server != null) { + server.shutdownAndWait(); + } + } + } } From a72646c5001f525ff2759db78c2d295e75118d38 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:23:13 +0300 Subject: [PATCH 326/492] Hold INCOMING_EVENTS context as a constant --- .../chatbot/IncomingEventsController.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index 7abcbe81..b92d2bb5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -20,9 +20,11 @@ package io.spine.chatbot; +import io.micronaut.context.event.ShutdownEvent; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; +import io.micronaut.runtime.event.annotation.EventListener; import io.spine.chatbot.google.chat.incoming.ChatEvent; import io.spine.chatbot.google.chat.incoming.User; import io.spine.core.UserId; @@ -32,7 +34,6 @@ import io.spine.server.integration.ThirdPartyContext; import static io.micronaut.http.MediaType.APPLICATION_JSON; -import static io.spine.util.Exceptions.newIllegalStateException; /** * A REST controller for handling incoming events from Google Chat. @@ -40,7 +41,8 @@ @Controller("/chat") final class IncomingEventsController implements Logging { - private static final String CONTEXT_NAME = "IncomingChatEvents"; + private static final ThirdPartyContext INCOMING_EVENTS = + ThirdPartyContext.singleTenant("IncomingChatEvents"); /** * Processes an incoming Google Chat event. @@ -55,11 +57,7 @@ String on(@Body PubsubPushRequest pushNotification) { _debug().log("Received a new chat event: %s", chatEventJson); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); var actor = eventActor(chatEvent.getUser()); - try (ThirdPartyContext incomingEvents = ThirdPartyContext.singleTenant(CONTEXT_NAME)) { - incomingEvents.emittedEvent(chatEvent, actor); - } catch (Exception e) { - throw newIllegalStateException(e, "Unable to handle incoming Google Chat event."); - } + INCOMING_EVENTS.emittedEvent(chatEvent, actor); return "OK"; } @@ -69,4 +67,18 @@ private static UserId eventActor(User user) { .setValue(user.getName()) .vBuild(); } + + /** + * Cleans up resources of the {@link #INCOMING_EVENTS context}. + */ + @EventListener + void on(ShutdownEvent event) { + _info().log("Closing IncomingChatEvents third-party context."); + try { + INCOMING_EVENTS.close(); + } catch (Exception e) { + _error().withCause(e) + .log("Unable to gracefully close IncomingChatEvents context."); + } + } } From 1e20bdd78c076fe83abe06e1c4e8f89e079429cd Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:23:42 +0300 Subject: [PATCH 327/492] Fix misprint --- .../src/main/java/io/spine/chatbot/RepositoriesController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 72386651..407a59c4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -41,7 +41,7 @@ final class RepositoriesController implements Logging { */ @Post("/builds/check") String checkBuildStatuses() { - _debug().log("Checking repositories build statues."); + _debug().log("Checking repositories build statuses."); try (var client = Client.inProcessClient(SERVER_NAME)) { var organizations = client.listOrganizations(); for (var organization : organizations) { From 05a9caa42fd9d1ce31e9fdeb3dc7a6df7cab1777 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:25:11 +0300 Subject: [PATCH 328/492] Add missing NPE check --- .../io/spine/chatbot/api/google/chat/BuildStateUpdates.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 383df33f..022ac927 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -29,12 +29,13 @@ import com.google.common.collect.ImmutableList; import io.spine.chatbot.github.repository.build.BuildState; import io.spine.chatbot.google.chat.thread.ThreadResource; -import io.spine.protobuf.Messages; +import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.chatbot.api.google.chat.ChatWidgets.cardWith; import static io.spine.chatbot.api.google.chat.ChatWidgets.linkButton; import static io.spine.chatbot.api.google.chat.ChatWidgets.sectionWithWidget; import static io.spine.chatbot.api.google.chat.ChatWidgets.textParagraph; +import static io.spine.protobuf.Messages.isNotDefault; import static io.spine.validate.Validate.checkValid; /** @@ -61,6 +62,7 @@ private BuildStateUpdates() { */ static Message buildStateMessage(BuildState buildState, ThreadResource thread) { checkValid(buildState); + checkNotNull(thread); var headerIcon = buildState.failed() ? FAILURE_ICON : SUCCESS_ICON; var cardHeader = new CardHeader() .setTitle(buildState.getRepositorySlug()) @@ -71,7 +73,7 @@ static Message buildStateMessage(BuildState buildState, ThreadResource thread) { actions(buildState) ); var message = new Message().setCards(cardWith(cardHeader, sections)); - if (Messages.isNotDefault(thread)) { + if (isNotDefault(thread)) { message.setThread(new Thread().setName(thread.getName())); } return message; From 03c5eb9dcc152a31ae205c19ddabbf6eeea7f9e9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:25:54 +0300 Subject: [PATCH 329/492] Cleanup docs --- .../java/io/spine/chatbot/api/google/chat/ChatWidgets.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java index 62a212f7..d28c78c3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java @@ -37,7 +37,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** - * A utility class that provides helper methods for creating Google Chat rich messages. + * Provides building blocks to empower the rich messages sent to Google Chat. */ final class ChatWidgets { @@ -64,7 +64,7 @@ private static OnClick openLink(Url url) { } /** - * Creates a singleton cards list with a new {@link Card} with a specified {@code header} + * Creates a singleton card list with a new {@link Card} with a specified {@code header} * and {@code sections}. */ static ImmutableList cardWith(CardHeader header, List

sections) { From 13153df2046f27dea1c51adff75894674835941e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:31:47 +0300 Subject: [PATCH 330/492] Add missing EOF --- .idea/inspectionProfiles/Project_Default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 4949f9cb..bf686044 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -857,4 +857,4 @@ - \ No newline at end of file + From b100b0c7d1af511f0f6ee704f1d8fd4e58fd34a6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:38:04 +0300 Subject: [PATCH 331/492] Fix naming and log --- .../main/java/io/spine/chatbot/RepositoriesController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 407a59c4..87d6b469 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -52,13 +52,13 @@ String checkBuildStatuses() { } } - private void checkBuildStatus(Client botClient, + private void checkBuildStatus(Client client, RepositoryId repository, Organization organization) { - _info().log("Sending `CheckRepositoryBuild` command for repository `%s`", + _info().log("Sending `CheckRepositoryBuild` command for the repository `%s`.", repository.getValue()); var checkRepositoryBuild = checkRepoBuildCommand(repository, organization); - botClient.post(checkRepositoryBuild); + client.post(checkRepositoryBuild); } private static CheckRepositoryBuild From 4868179fb734dbc534c6b7e67efa48a1e4e5d7c6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:38:21 +0300 Subject: [PATCH 332/492] Cleanup docs --- .../spine/chatbot/api/google/chat/GoogleChat.java | 13 ++++++------- .../spine/chatbot/api/google/chat/package-info.java | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 6717efe3..cdf454ad 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -41,19 +41,19 @@ import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; /** - * Google Chat Hangouts API client. + * Google Chat API client. * - * @see Hangouts Chat API + * @see Google Chat API */ public final class GoogleChat implements GoogleChatClient, Logging { private static final String BOT_NAME = "Spine Chat Bot"; private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; - private final HangoutsChat hangoutsChat; + private final HangoutsChat chat; private GoogleChat(HangoutsChat chat) { - hangoutsChat = chat; + this.chat = chat; } /** @@ -84,14 +84,13 @@ public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread @CanIgnoreReturnValue private Message sendMessage(String space, Message message) { try { - return hangoutsChat + return chat .spaces() .messages() .create(space, message) .execute(); } catch (IOException e) { - logger().atSevere() - .withCause(e) + _error().withCause(e) .log("Unable to send message to space `%s`.", space); throw new RuntimeException("Unable to send message to space " + space, e); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java index 07d2a108..5868f089 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java @@ -21,7 +21,7 @@ /** * This package contains Google Chat API facade. * - *

The usage of the Chat API itself it not straight-forward that's why it is recommended to + *

The usage of the Chat API itself it not straight-forward. That's why it is recommended to * use the {@link io.spine.chatbot.api.google.chat.GoogleChatClient facade} instead. */ @CheckReturnValue From fa842de545e34a41f88e4fbcb66d1fd61518a0eb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:38:48 +0300 Subject: [PATCH 333/492] Cleanup code and extract `stateLabel` functionality into the mixin --- .../api/google/chat/BuildStateUpdates.java | 41 ++++++++----------- .../server/github/BuildStateMixin.java | 10 +++++ 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 022ac927..848a9521 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -60,17 +60,17 @@ private BuildStateUpdates() { *

If the thread has no name set, assumes that the update message should be * sent to a new thread. */ - static Message buildStateMessage(BuildState buildState, ThreadResource thread) { - checkValid(buildState); + static Message buildStateMessage(BuildState build, ThreadResource thread) { + checkValid(build); checkNotNull(thread); - var headerIcon = buildState.failed() ? FAILURE_ICON : SUCCESS_ICON; + var headerIcon = build.failed() ? FAILURE_ICON : SUCCESS_ICON; var cardHeader = new CardHeader() - .setTitle(buildState.getRepositorySlug()) + .setTitle(build.getRepositorySlug()) .setImageUrl(headerIcon); var sections = ImmutableList.of( - buildStateSection(buildState), - commitSection(buildState.getLastCommit()), - actions(buildState) + buildStateSection(build), + commitSection(build), + actions(build) ); var message = new Message().setCards(cardWith(cardHeader, sections)); if (isNotDefault(thread)) { @@ -79,7 +79,8 @@ static Message buildStateMessage(BuildState buildState, ThreadResource thread) { return message; } - private static Section commitSection(BuildState.Commit commit) { + private static Section commitSection(BuildState build) { + var commit = build.getLastCommit(); var commitInfo = String.format( "Authored by %s at %s.", commit.getAuthoredBy(), commit.getCommittedAt() ); @@ -92,30 +93,24 @@ private static Section commitSection(BuildState.Commit commit) { return section; } - private static Section actions(BuildState buildState) { - BuildState.Commit commit = buildState.getLastCommit(); - WidgetMarkup actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( - linkButton("Build", buildState.getTravisCiUrl()), + private static Section actions(BuildState build) { + var commit = build.getLastCommit(); + var actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( + linkButton("Build", build.getTravisCiUrl()), linkButton("Changeset", commit.getCompareUrl()) )); return sectionWithWidget(actionButtons); } - private static Section buildStateSection(BuildState buildState) { - return sectionWithWidget(buildStateWidget(buildState)); + private static Section buildStateSection(BuildState build) { + return sectionWithWidget(buildStateWidget(build)); } - private static WidgetMarkup buildStateWidget(BuildState buildState) { + private static WidgetMarkup buildStateWidget(BuildState build) { var keyValue = new KeyValue() .setTopLabel("Build No.") - .setContent(buildState.getNumber()) - .setBottomLabel(capitalizeState(buildState.getState())); + .setContent(build.getNumber()) + .setBottomLabel(build.stateLabel()); return new WidgetMarkup().setKeyValue(keyValue); } - - private static String capitalizeState(BuildState.State state) { - var name = state.name(); - return name.charAt(0) + name.substring(1) - .toLowerCase(); - } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java index 0a32192f..86ad29f3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -52,6 +52,16 @@ default boolean failed() { return failed(getState()); } + /** + * Returns a capitalized label of the {@link BuildState.State build state}. + */ + default String stateLabel() { + var state = getState(); + var name = state.name(); + return name.charAt(0) + name.substring(1) + .toLowerCase(); + } + /** * Creates an instance of the {@link BuildState.State build state} of out its * string representation. From e23f921a81ecc30976f29cd717e4ebcae39dac9b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 07:49:08 +0300 Subject: [PATCH 334/492] Extract creation of the HangoutsChat instance into a subclass --- .../chatbot/api/google/chat/GoogleChat.java | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index cdf454ad..596a116c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -21,6 +21,7 @@ package io.spine.chatbot.api.google.chat; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.chat.v1.HangoutsChat; import com.google.api.services.chat.v1.model.Message; @@ -39,6 +40,7 @@ import java.security.GeneralSecurityException; import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; +import static io.spine.util.Exceptions.newIllegalStateException; /** * Google Chat API client. @@ -62,7 +64,7 @@ private GoogleChat(HangoutsChat chat) { *

The client is backed by {@link HangoutsChat} API. */ public static GoogleChatClient newInstance() { - return new GoogleChat(hangoutsChat()); + return new GoogleChat(HangoutsChatProvider.newHangoutsChat()); } @Override @@ -96,30 +98,56 @@ private Message sendMessage(String space, Message message) { } } - private static HangoutsChat hangoutsChat() { - try { - var serviceAccount = Secrets.chatServiceAccount(); - var credentials = GoogleCredentials.fromStream(streamFrom(serviceAccount)) - .createScoped(CHAT_BOT_SCOPE); - var credentialsAdapter = new HttpCredentialsAdapter(credentials); - var chat = new HangoutsChat.Builder( - GoogleNetHttpTransport.newTrustedTransport(), - JacksonFactory.getDefaultInstance(), - credentialsAdapter) + /** + * Provides fully-configured {@link HangoutsChat chat} client. + */ + private static class HangoutsChatProvider { + + /** + * Prevents direct instantiation of the utility class. + */ + private HangoutsChatProvider() { + } + + /** + * Creates a new instance of the {@link HangoutsChat} client. + */ + private static HangoutsChat newHangoutsChat() { + HttpCredentialsAdapter credentialsAdapter = newCredentialsHelper(); + var chat = chatWithCredentials(credentialsAdapter) .setApplicationName(BOT_NAME) .build(); return chat; - } catch (IOException | GeneralSecurityException e) { - String message = "Unable to create Hangouts Chat client."; - Logging.loggerFor(GoogleChat.class) - .atSevere() - .withCause(e) - .log(message); - throw new RuntimeException(message, e); } - } - private static InputStream streamFrom(String data) { - return new ByteArrayInputStream(data.getBytes(Charset.defaultCharset())); + private static HttpCredentialsAdapter newCredentialsHelper() { + try { + var serviceAccount = Secrets.chatServiceAccount(); + var credentials = GoogleCredentials.fromStream(streamFrom(serviceAccount)) + .createScoped(CHAT_BOT_SCOPE); + return new HttpCredentialsAdapter(credentials); + } catch (IOException e) { + throw newIllegalStateException(e, "Unable to read GoogleCredentials."); + } + } + + private static HangoutsChat.Builder + chatWithCredentials(HttpCredentialsAdapter credentialsAdapter) { + var transport = newTrustedTransport(); + var jacksonFactory = JacksonFactory.getDefaultInstance(); + return new HangoutsChat.Builder(transport, jacksonFactory, credentialsAdapter); + } + + private static HttpTransport newTrustedTransport() { + try { + return GoogleNetHttpTransport.newTrustedTransport(); + } catch (GeneralSecurityException | IOException e) { + throw newIllegalStateException(e, "Unable to instantiate trusted transport."); + } + } + + private static InputStream streamFrom(String data) { + return new ByteArrayInputStream(data.getBytes(Charset.defaultCharset())); + } } } From f5ecc449c40ca5745783e2636a66727e4f1b6fc2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:07:56 +0300 Subject: [PATCH 335/492] Cleanup docs --- .../main/java/io/spine/chatbot/api/travis/BuildsQuery.java | 6 +++--- .../src/main/java/io/spine/chatbot/api/travis/Query.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index 2c57bc88..a790bbb1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -21,7 +21,7 @@ package io.spine.chatbot.api.travis; /** - * Travis CI branch builds API query. + * Travis CI API query for finding repo branch builds. * * @see Find branch build */ @@ -32,9 +32,9 @@ private BuildsQuery(String request) { } /** - * Creates a repository branch builds query for a repository with the specified {@code slug}. + * Creates a query for a repository with the specified {@code slug}. * - *

Requests only a single build from the {@code master} branch + *

Requests the latest build from the {@code master} branch. */ public static BuildsQuery forRepo(String repoSlug) { var encodedSlug = encode(repoSlug); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java index 86f15ea6..7a2f0e0e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java @@ -29,7 +29,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** - * A Travis CI API query. + * A query to the Travis CI API. * * @param * type of the expected query execution response @@ -48,7 +48,7 @@ public abstract class Query { } /** - * Returns query REST request URL. + * Returns the request URL to the REST endpoint. */ String request() { return request; @@ -62,7 +62,7 @@ Class responseType() { } /** - * Encodes passed value using {@link URLEncoder} and standard + * Encodes passed value using {@link URLEncoder} and * {@link StandardCharsets#UTF_8 UTF_8} charset. */ static String encode(String value) { From 883fccb8512012ddd9b3b2fdb881251164bb0113 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:08:58 +0300 Subject: [PATCH 336/492] Shorten the parameter --- .../src/main/java/io/spine/chatbot/client/Client.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index 537c773e..62157085 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -73,11 +73,11 @@ public ImmutableList listOrganizations() { /** * Returns list of all registered repositories for the {@code organization}. */ - public ImmutableList listOrgRepos(OrganizationId organization) { - checkNotNull(organization); + public ImmutableList listOrgRepos(OrganizationId org) { + checkNotNull(org); var orgRepos = client.asGuest() .select(OrganizationRepositories.class) - .byId(organization) + .byId(org) .run(); checkState(orgRepos.size() == 1); return ImmutableList.copyOf(orgRepos.get(0) From ef870eeca3f02011a088f9f767bb74e27f90d035 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:13:08 +0300 Subject: [PATCH 337/492] Improve docs --- .../spine/chatbot/server/github/BuildStateMixin.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java index 86ad29f3..e89f9805 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -82,10 +82,10 @@ static BuildState.State buildStateFrom(String state) { * Determines the {@link BuildStateStatusChange status chage} of the build comparing to the * {@code previousState}. * - * @see #stateStatusChangeOf(BuildStateMixin, BuildStateMixin) + * @see #statusChange(BuildStateMixin, BuildStateMixin) */ default BuildStateStatusChange stateChangeFrom(BuildStateMixin previousState) { - return stateStatusChangeOf(this, previousState); + return statusChange(this, previousState); } /** @@ -101,8 +101,8 @@ default BuildStateStatusChange stateChangeFrom(BuildStateMixin previousState) { * {@code unknown} meaning that there were no previous states or {@code passed} as well. * */ - private static BuildStateStatusChange stateStatusChangeOf(BuildStateMixin newBuildState, - BuildStateMixin previousBuildState) { + private static BuildStateStatusChange statusChange(BuildStateMixin newBuildState, + BuildStateMixin previousBuildState) { var currentState = newBuildState.getState(); var previousState = previousBuildState.getState(); if (newBuildState.failed()) { @@ -126,7 +126,7 @@ private static BuildStateStatusChange stateStatusChangeOf(BuildStateMixin newBui *

The {@code cancelled}, {@code failed} and {@code errored} statuses are considered * failed statuses. * - * @return `true` if the build status is failed, `false` otherwise + * @return {@code true} if the build status is failed, {@code false} otherwise */ private static boolean failed(BuildState.State state) { var failedStatuses = EnumSet.of( From c453354c97e70f7f02b4f6834aadabd8c3cc59c6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:17:26 +0300 Subject: [PATCH 338/492] Cleanup namings --- .../java/io/spine/chatbot/Application.java | 4 +-- .../chatbot/server/github/GitHubContext.java | 31 +++++++++---------- .../server/google/chat/GoogleChatContext.java | 27 ++++++++-------- .../chatbot/IncomingEventsControllerTest.java | 2 +- .../server/github/GitHubContextAwareTest.java | 2 +- .../chat/GoogleChatContextAwareTest.java | 4 +-- .../google/chat/GoogleChatContextTest.java | 4 +-- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 2e45d603..cbbeca02 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -111,8 +111,8 @@ private void start(String[] args) { static Server startServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { Server server = Server .inProcess(SERVER_NAME) - .add(gitHubContext.contextBuilder()) - .add(googleChatContext.contextBuilder()) + .add(gitHubContext.builder()) + .add(googleChatContext.builder()) .build(); try { server.start(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 7d0a22ad..7e9845aa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -37,27 +37,27 @@ public final class GitHubContext { */ static final String GIT_HUB_CONTEXT_NAME = "GitHub"; - private final BoundedContextBuilder contextBuilder; + private final BoundedContextBuilder builder; - private GitHubContext(TravisClient travisClient) { - this.contextBuilder = configureContextBuilder(travisClient); + private GitHubContext(TravisClient client) { + this.builder = configureBuilder(client); } /** * Returns the context builder associated with the GitHub context. */ - public BoundedContextBuilder contextBuilder() { - return this.contextBuilder; + public BoundedContextBuilder builder() { + return this.builder; } - private static BoundedContextBuilder configureContextBuilder(TravisClient travisClient) { + private static BoundedContextBuilder configureBuilder(TravisClient client) { return BoundedContext .singleTenant(GIT_HUB_CONTEXT_NAME) .add(OrganizationAggregate.class) .add(RepositoryAggregate.class) .add(new OrgReposRepository()) - .add(new SpineOrgInitRepository(travisClient)) - .add(new RepoBuildRepository(travisClient)); + .add(new SpineOrgInitRepository(client)) + .add(new RepoBuildRepository(client)); } /** @@ -72,7 +72,7 @@ public static Builder newBuilder() { */ public static final class Builder { - private TravisClient travisClient; + private TravisClient client; /** * Prevents direct instantiation. @@ -83,23 +83,22 @@ private Builder() { /** * Sets Travis CI client to be used within the context. */ - public Builder setTravis(TravisClient travisClient) { - checkNotNull(travisClient); - this.travisClient = travisClient; + public Builder setTravis(TravisClient client) { + this.client = checkNotNull(client); return this; } /** * Finishes configuration of the context and builds a new instance. * - *

If the {@link #travisClient} was not explicitly configured, uses the + *

If the {@link #client} was not explicitly configured, uses the * {@link Travis#newInstance() default} client. */ public GitHubContext build() { - if (travisClient == null) { - travisClient = Travis.newInstance(); + if (client == null) { + client = Travis.newInstance(); } - return new GitHubContext(travisClient); + return new GitHubContext(client); } } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index ca9e50ef..46a91012 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -35,29 +35,29 @@ public final class GoogleChatContext { /** The name of the Google Chat Context. **/ static final String GOOGLE_CHAT_CONTEXT_NAME = "GoogleChat"; - private final BoundedContextBuilder contextBuilder; + private final BoundedContextBuilder builder; - private GoogleChatContext(GoogleChatClient googleChatClient) { - this.contextBuilder = configureContextBuilder(googleChatClient); + private GoogleChatContext(GoogleChatClient client) { + this.builder = configureBuilder(client); } /** * Returns the context builder associated with the Google Chat context. */ - public BoundedContextBuilder contextBuilder() { - return this.contextBuilder; + public BoundedContextBuilder builder() { + return this.builder; } /** * Creates a new instance of the Google Chat context builder. */ private static BoundedContextBuilder - configureContextBuilder(GoogleChatClient googleChatClient) { + configureBuilder(GoogleChatClient client) { return BoundedContext .singleTenant(GOOGLE_CHAT_CONTEXT_NAME) .add(new SpaceRepository()) .add(new ThreadRepository()) - .add(new ThreadChatRepository(googleChatClient)) + .add(new ThreadChatRepository(client)) .addEventDispatcher(new IncomingEventsHandler()); } @@ -73,7 +73,7 @@ public static Builder newBuilder() { */ public static final class Builder { - private GoogleChatClient googleChatClient; + private GoogleChatClient client; /** * Prevents direct instantiation. @@ -84,9 +84,8 @@ private Builder() { /** * Sets Google Chat client to be used within the context. */ - public Builder setGoogleChatClient(GoogleChatClient googleChatClient) { - checkNotNull(googleChatClient); - this.googleChatClient = googleChatClient; + public Builder setClient(GoogleChatClient client) { + this.client = checkNotNull(client); return this; } @@ -94,10 +93,10 @@ public Builder setGoogleChatClient(GoogleChatClient googleChatClient) { * Finishes configuration of the context and builds a new instance. */ public GoogleChatContext build() { - if (googleChatClient == null) { - googleChatClient = GoogleChat.newInstance(); + if (client == null) { + client = GoogleChat.newInstance(); } - return new GoogleChatContext(googleChatClient); + return new GoogleChatContext(client); } } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index ea3bc817..67913b5f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -59,7 +59,7 @@ final class IncomingEventsControllerTest { static void setupServer() { var chatContext = GoogleChatContext .newBuilder() - .setGoogleChatClient(InMemoryGoogleChatClient.lenientClient()) + .setClient(InMemoryGoogleChatClient.lenientClient()) .build(); var gitHubContext = GitHubContext .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java index 8daba455..2e919a4c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java @@ -39,7 +39,7 @@ protected final BoundedContextBuilder contextBuilder() { .newBuilder() .setTravis(travisClient) .build() - .contextBuilder(); + .builder(); } @AfterEach diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java index 642493ad..684df73c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java @@ -37,9 +37,9 @@ abstract class GoogleChatContextAwareTest extends ContextAwareTest { protected final BoundedContextBuilder contextBuilder() { return GoogleChatContext .newBuilder() - .setGoogleChatClient(googleChatClient) + .setClient(googleChatClient) .build() - .contextBuilder(); + .builder(); } @AfterEach diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java index 64f6dd0c..abfb176a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -36,7 +36,7 @@ void allowConfiguringTravisClient() { assertDoesNotThrow( () -> GoogleChatContext .newBuilder() - .setGoogleChatClient(InMemoryGoogleChatClient.lenientClient()) + .setClient(InMemoryGoogleChatClient.lenientClient()) .build() ); } @@ -47,7 +47,7 @@ void allowConfiguringTravisClient() { void notAllowNullTravisClients() { assertThrows( NullPointerException.class, () -> GoogleChatContext.newBuilder() - .setGoogleChatClient(null) + .setClient(null) ); } } From ce3fd5e847e5d2164b74509972c98270273e36f4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:26:18 +0300 Subject: [PATCH 339/492] Cleanup docs --- .../io/spine/chatbot/delivery/DistributedDelivery.java | 5 +++-- .../java/io/spine/chatbot/delivery/ShardDelivery.java | 10 ++++++++-- .../java/io/spine/chatbot/delivery/package-info.java | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java index 3a15aa3d..133400af 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java @@ -27,7 +27,7 @@ import io.spine.server.storage.datastore.DsShardedWorkRegistry; /** - * A distributed cloud environment {@link Delivery}. + * Delivers messages using Datastore as the underlying storage. * *

The delivery is based on the {@link DatastoreStorageFactory Datastore} and uses * {@link DsShardedWorkRegistry} as the {@link ShardedWorkRegistry work registry}. @@ -46,7 +46,8 @@ private DistributedDelivery() { /** * Creates a new Datastore-based delivery using the supplied Datastore {@code storageFactory}. * - *

Uses uniformly sharded strategy and single-tenant inbox storage. + *

Assigns the targets uniformly across shards. Configures the inbox storage + * to be single-tenant. */ public static Delivery instance(DatastoreStorageFactory storageFactory) { var workRegistry = new DsShardedWorkRegistry(storageFactory); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java index 4bc3b01f..313a71f6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -27,7 +27,12 @@ import io.spine.server.delivery.ShardedRecord; /** - * Delivery of messages from a particular shard. + * Performs the delivery of the messages from a particular shard. + * + *

Wraps the {@link io.spine.server.delivery.Delivery#deliverMessagesFrom(ShardIndex) + * Delivery#deliverMessagesFrom} + * with server environment-specific logging and provides helpers that unifies the usage of the + * delivery. */ final class ShardDelivery implements Logging { @@ -59,7 +64,8 @@ private void deliverNow() { var indexValue = shard.getIndex(); _trace().log("Delivering messages from shard with index `%d`. NodeId=%s.", indexValue, nodeId); - var stats = server.delivery().deliverMessagesFrom(shard); + var stats = server.delivery() + .deliverMessagesFrom(shard); if (stats.isPresent()) { DeliveryStats deliveryStats = stats.get(); _trace().log("`%d` messages delivered from shard with index `%s`. NodeId=%s.", diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java index 02227dfc..dc021563 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/package-info.java @@ -19,7 +19,7 @@ */ /** - * This package contains the ChatBot signals delivery configurations. + * This package is devoted to configuring the delivery mechanism for ChatBot signals. */ @CheckReturnValue @ParametersAreNonnullByDefault From 8e7799af82e2e611023e284b94f427ebd024b968 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:32:18 +0300 Subject: [PATCH 340/492] Fix formatting --- .../io/spine/chatbot/server/github/OrgReposRepository.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java index 383ada7a..cf1e884d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java @@ -35,9 +35,7 @@ * The repository for {@link OrganizationRepositories}. */ final class OrgReposRepository - extends ProjectionRepository { + extends ProjectionRepository { @OverridingMethodsMustInvokeSuper @Override From 08d2002e089894ffeefec6b7995f9ea54a764b52 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:32:25 +0300 Subject: [PATCH 341/492] Improve docs --- .../io/spine/chatbot/server/github/OrgReposProjection.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java index 0f109dc6..053df79e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java @@ -31,7 +31,9 @@ /** * Organization repositories projection. * - *

Holds IDs of all registered repositories in the organization. + *

Repositories are only referenced by their identifiers. + * See {@link io.spine.chatbot.github.repository.Repository Repository} for the details + * on each repository. */ final class OrgReposProjection extends Projection { From b7a37ae6f5acda79ae0b651439273449ef148292 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:33:11 +0300 Subject: [PATCH 342/492] use notEmptyOrBlank checks instead of notNull --- .../io/spine/chatbot/server/github/GitHubIdentifier.java | 6 +++--- .../chatbot/server/google/chat/GoogleChatIdentifier.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java index 31e71b63..fc7fc029 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java @@ -23,7 +23,7 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; -import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** * A utility for working with {@link GitHubContext} identifiers. @@ -40,7 +40,7 @@ private GitHubIdentifier() { * Creates a new {@link OrganizationId} out of the specified {@code name}. */ public static OrganizationId organization(String name) { - checkNotNull(name); + checkNotEmptyOrBlank(name); return OrganizationId .newBuilder() .setValue(name) @@ -51,7 +51,7 @@ public static OrganizationId organization(String name) { * Creates a new {@link RepositoryId} out of the specified {@code slug}. */ public static RepositoryId repository(String slug) { - checkNotNull(slug); + checkNotEmptyOrBlank(slug); return RepositoryId .newBuilder() .setValue(slug) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java index 960cfa3e..4fb7fa65 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java @@ -24,7 +24,7 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.ThreadId; -import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** * A utility for working with {@link GoogleChatContext} identifiers. @@ -41,7 +41,7 @@ private GoogleChatIdentifier() { * Creates a new {@link ThreadId} out of the specified {@code value}. */ public static ThreadId thread(String value) { - checkNotNull(value); + checkNotEmptyOrBlank(value); return ThreadId .newBuilder() .setValue(value) @@ -52,7 +52,7 @@ public static ThreadId thread(String value) { * Creates a new {@link SpaceId} out of the specified {@code value}. */ public static SpaceId space(String value) { - checkNotNull(value); + checkNotEmptyOrBlank(value); return SpaceId .newBuilder() .setValue(value) @@ -63,7 +63,7 @@ public static SpaceId space(String value) { * Creates a new {@link MessageId} out of the specified {@code value}. */ public static MessageId message(String value) { - checkNotNull(value); + checkNotEmptyOrBlank(value); return MessageId .newBuilder() .setValue(value) From b4719a357f49dffb6fc8ac774bfe6f90fa160b92 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:36:46 +0300 Subject: [PATCH 343/492] Cleanup code, extract helper methods --- .../server/github/RepoBuildProcess.java | 66 ++++++++++++------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 35ac9adf..ae985513 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -48,7 +48,7 @@ import static io.spine.util.Exceptions.newIllegalStateException; /** - * A repository build process. + * Verifies a status of a build of a repository. * *

Performs repository build checks and acknowledges the state of the repository builds. * As a result, emits build status events such as: @@ -56,7 +56,7 @@ *

    *
  • {@link BuildFailed} — whenever the build is failed; *
  • {@link BuildRecovered} — whenever the build state changes from {@code failed} - * to {@code passing}. + * to {@code passing}; *
  • {@link BuildStable} — whenever the build state is {@code passing} and was * {@code passing} previously. *
@@ -80,7 +80,7 @@ final class RepoBuildProcess EitherOf3 handle(CheckRepositoryBuild c) throws NoBuildsFound { var repository = c.getRepository(); - _info().log("Checking build status for repository `%s`.", repository.getValue()); + _info().log("Checking build status for the repository `%s`.", repository.getValue()); var branchBuild = client.execute(BuildsQuery.forRepo(repository.getValue())); if (isDefault(branchBuild.getLastBuild())) { _warn().log("No builds found for the repository `%s`.", repository.getValue()); @@ -109,30 +109,11 @@ EitherOf3 handle(CheckRepositoryBuild var stateStatusChange = newBuildState.stateChangeFrom(previousBuildState); switch (stateStatusChange) { case FAILED: - _info().log("Build for repository `%s` failed with status `%s`.", - repository.getValue(), newBuildState.getState()); - var buildFailed = BuildFailed - .newBuilder() - .setRepository(repository) - .setChange(stateChange) - .vBuild(); - return EitherOf3.withA(buildFailed); + return onFailed(repository, stateChange); case RECOVERED: - _info().log("Build for repository `%s` is recovered.", repository.getValue()); - var buildRecovered = BuildRecovered - .newBuilder() - .setRepository(repository) - .setChange(stateChange) - .vBuild(); - return EitherOf3.withB(buildRecovered); + return onRecovered(repository, stateChange); case STABLE: - _info().log("Build for repository `%s` is stable.", repository.getValue()); - var buildStable = BuildStable - .newBuilder() - .setRepository(repository) - .setChange(stateChange) - .vBuild(); - return EitherOf3.withC(buildStable); + return onStable(repository, stateChange); case BSC_UNKNOWN: case UNRECOGNIZED: default: @@ -142,6 +123,41 @@ EitherOf3 handle(CheckRepositoryBuild } } + private EitherOf3 + onStable(RepositoryId repository, BuildStateChange stateChange) { + _info().log("Build for the repository `%s` is stable.", repository.getValue()); + var buildStable = BuildStable + .newBuilder() + .setRepository(repository) + .setChange(stateChange) + .vBuild(); + return EitherOf3.withC(buildStable); + } + + private EitherOf3 + onRecovered(RepositoryId repository, BuildStateChange stateChange) { + _info().log("Build for the repository `%s` is recovered.", repository.getValue()); + var buildRecovered = BuildRecovered + .newBuilder() + .setRepository(repository) + .setChange(stateChange) + .vBuild(); + return EitherOf3.withB(buildRecovered); + } + + private EitherOf3 + onFailed(RepositoryId repository, BuildStateChange stateChange) { + var newBuildState = stateChange.getNewValue(); + _info().log("Build for the repository `%s` failed with status `%s`.", + repository.getValue(), newBuildState.getState()); + var buildFailed = BuildFailed + .newBuilder() + .setRepository(repository) + .setChange(stateChange) + .vBuild(); + return EitherOf3.withA(buildFailed); + } + @VisibleForTesting static BuildState buildStateFrom(RepoBranchBuildResponse branchBuild, String space) { var branchBuildName = branchBuild.getName(); From 9cd2f54b8291dc7910937f50a079d430eff1474d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:40:41 +0300 Subject: [PATCH 344/492] Rename `travisClient` to `client` --- .../io/spine/chatbot/server/github/RepoBuildRepository.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java index 8423e290..c623618a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java @@ -31,15 +31,15 @@ final class RepoBuildRepository extends ProcessManagerRepository { - private final TravisClient travisClient; + private final TravisClient client; RepoBuildRepository(TravisClient client) { - travisClient = client; + this.client = client; } @Override protected void configure(RepoBuildProcess processManager) { super.configure(processManager); - processManager.setClient(travisClient); + processManager.setClient(client); } } From 162006488e93079ff17bb4ebd3a74ed2ce1b88f5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:43:30 +0300 Subject: [PATCH 345/492] Rename `BuildStable` to `BuildSucceededAgain` --- .../server/github/RepoBuildProcess.java | 18 +++++++++--------- .../github/repository_build_events.proto | 2 +- .../server/github/RepoBuildProcessTest.java | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index ae985513..91dac0f1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -34,7 +34,7 @@ import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; -import io.spine.chatbot.github.repository.build.event.BuildStable; +import io.spine.chatbot.github.repository.build.event.BuildSucceededAgain; import io.spine.chatbot.github.repository.build.rejection.NoBuildsFound; import io.spine.logging.Logging; import io.spine.net.Urls; @@ -57,7 +57,7 @@ *
  • {@link BuildFailed} — whenever the build is failed; *
  • {@link BuildRecovered} — whenever the build state changes from {@code failed} * to {@code passing}; - *
  • {@link BuildStable} — whenever the build state is {@code passing} and was + *
  • {@link BuildSucceededAgain} — whenever the build state is {@code passing} and was * {@code passing} previously. * * @@ -77,7 +77,7 @@ final class RepoBuildProcess * throws {@link NoBuildsFound} rejection. */ @Assign - EitherOf3 handle(CheckRepositoryBuild c) + EitherOf3 handle(CheckRepositoryBuild c) throws NoBuildsFound { var repository = c.getRepository(); _info().log("Checking build status for the repository `%s`.", repository.getValue()); @@ -102,7 +102,7 @@ EitherOf3 handle(CheckRepositoryBuild return result; } - private EitherOf3 + private EitherOf3 determineOutcome(RepositoryId repository, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); var previousBuildState = stateChange.getPreviousValue(); @@ -123,18 +123,18 @@ EitherOf3 handle(CheckRepositoryBuild } } - private EitherOf3 + private EitherOf3 onStable(RepositoryId repository, BuildStateChange stateChange) { _info().log("Build for the repository `%s` is stable.", repository.getValue()); - var buildStable = BuildStable + var buildSucceededAgain = BuildSucceededAgain .newBuilder() .setRepository(repository) .setChange(stateChange) .vBuild(); - return EitherOf3.withC(buildStable); + return EitherOf3.withC(buildSucceededAgain); } - private EitherOf3 + private EitherOf3 onRecovered(RepositoryId repository, BuildStateChange stateChange) { _info().log("Build for the repository `%s` is recovered.", repository.getValue()); var buildRecovered = BuildRecovered @@ -145,7 +145,7 @@ EitherOf3 handle(CheckRepositoryBuild return EitherOf3.withB(buildRecovered); } - private EitherOf3 + private EitherOf3 onFailed(RepositoryId repository, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); _info().log("Build for the repository `%s` failed with status `%s`.", diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 5027b709..ccbd73ce 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -54,7 +54,7 @@ message BuildRecovered { } // The build is stable and passing. -message BuildStable { +message BuildSucceededAgain { RepositoryId repository = 1 [(required) = true]; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 492f01f0..bc59c2be 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -32,7 +32,7 @@ import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; -import io.spine.chatbot.github.repository.build.event.BuildStable; +import io.spine.chatbot.github.repository.build.event.BuildSucceededAgain; import io.spine.chatbot.github.repository.build.rejection.RepositoryBuildRejections; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -236,12 +236,12 @@ void producingEvent() { .setPreviousValue(previousBuildState) .setNewValue(newBuildState) .vBuild(); - var buildFailed = BuildStable + var buildSucceededAgain = BuildSucceededAgain .newBuilder() .setRepository(repository) .setChange(stateChange) .vBuild(); - context().assertEvent(buildFailed); + context().assertEvent(buildSucceededAgain); } @Test From 7027287a6ec3a5527b1f62db45c554803d1143d6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:43:36 +0300 Subject: [PATCH 346/492] Fix test --- .../chatbot/server/google/chat/GoogleChatIdentifierTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java index 7f24ca3c..01ce6f94 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java @@ -69,12 +69,12 @@ void messageIds(String value) { @SuppressWarnings("unused") // method is used as parameterized test source private Stream spaceIdsSource() { - return Stream.of("spaces/", "spacs/12415", "", " "); + return Stream.of("spaces/", "spacs/12415"); } @SuppressWarnings("unused") // method is used as parameterized test source private Stream messageIdsSource() { - return Stream.of("spaces/", "spaces/qwe124", "spaces/eqwt23/messages/", "", " "); + return Stream.of("spaces/", "spaces/qwe124", "spaces/eqwt23/messages/"); } } From 0ccca188ab5ef6908020b9a3f74b84015efa8520 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:43:56 +0300 Subject: [PATCH 347/492] Mark as `GeneratedMixin` and cleanup doc --- .../java/io/spine/chatbot/server/github/RepositoryAware.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java index 7f069cf4..e65c286b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java @@ -20,11 +20,13 @@ package io.spine.chatbot.server.github; +import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.github.RepositoryId; /** * Common interface for messages aware of the {@link RepositoryId repository}. */ +@GeneratedMixin public interface RepositoryAware { /** @@ -37,7 +39,7 @@ default RepositoryId repository() { /** * Obtains the repository ID. * - * @implNote this is the Protobuf-level accessor. + * @implNote This method is implemented in the deriving Protobuf messages. */ RepositoryId getRepository(); } From ac046bb4ab1ce42d205badbaf5d5b62a213c4c34 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:49:03 +0300 Subject: [PATCH 348/492] Drop extra constant --- .../server/github/RepoBuildProcess.java | 6 +++ .../server/github/SpineOrgInitProcess.java | 40 ++++++++++--------- .../server/github/SpineOrgInitRepository.java | 6 +-- .../github/SpineOrgInitProcessTest.java | 8 ++-- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 91dac0f1..04eb8f18 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -191,6 +191,12 @@ private static BuildState.Commit from(Commit commit) { .vBuild(); } + /** + * Sets {@link #client} to be used during handling of signals. + * + * @implNote the method is intended to be used as part of the entity configuration + * done through the repository + */ void setClient(TravisClient client) { this.client = client; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 175c1aac..0245217a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -45,7 +45,7 @@ import static io.spine.net.Urls.urlOfSpec; /** - * Spine Event Engine organization initialization process. + * Spine organization init process. * *

    Registers Spine organization and the watched {@link #WATCHED_REPOS repositories} upon adding * the ChatBot to the space. @@ -54,20 +54,18 @@ final class SpineOrgInitProcess extends ProcessManager implements Logging { - private static final String SPINE_ORG = "SpineEventEngine"; - private static final ImmutableList WATCHED_REPOS = ImmutableList.of( "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" ); /** The initialization process ID. **/ - static final OrganizationId SPINE_ORGANIZATION = organization(SPINE_ORG); + static final OrganizationId ORGANIZATION = organization("SpineEventEngine"); @LazyInit - private @MonotonicNonNull TravisClient travisClient; + private @MonotonicNonNull TravisClient client; /** - * Registers {@link #SPINE_ORGANIZATION Spine} organization and watched resources that are + * Registers {@link #ORGANIZATION Spine} organization and watched resources that are * currently available in the Travis CI. * *

    If a particular repository is not available in Travis, it is then skipped @@ -83,13 +81,13 @@ Iterable on(@External SpaceRegistered e) { .getValue(); _info().log("Starting Spine organization initialization process in space `%s`.", space); var commands = ImmutableSet.builder(); - commands.add(registerOrgCommand(SPINE_ORGANIZATION, space)); - travisClient.execute(ReposQuery.forOwner(SPINE_ORG)) - .getRepositoriesList() - .stream() - .filter(repository -> WATCHED_REPOS.contains(repository.getName())) - .map(repository -> registerRepoCommand(repository, SPINE_ORGANIZATION)) - .forEach(commands::add); + commands.add(registerOrgCommand(ORGANIZATION, space)); + client.execute(ReposQuery.forOwner(ORGANIZATION.getValue())) + .getRepositoriesList() + .stream() + .filter(repository -> WATCHED_REPOS.contains(repository.getName())) + .map(repository -> registerRepoCommand(repository, ORGANIZATION)) + .forEach(commands::add); builder().setGoogleChatSpace(space) .setInitialized(true); return commands.build(); @@ -109,19 +107,25 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o } private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, String spaceName) { - _info().log("Registering `%s` organization.", SPINE_ORG); + _info().log("Registering `%s` organization.", ORGANIZATION.getValue()); return RegisterOrganization .newBuilder() .setId(spineOrgId) .setName("Spine Event Engine") .setWebsiteUrl(urlOfSpec("https://spine.io/")) - .setTravisCiUrl(travisUrlFor(SPINE_ORG)) - .setGithubUrl(githubUrlFor(SPINE_ORG)) + .setTravisCiUrl(travisUrlFor(ORGANIZATION.getValue())) + .setGithubUrl(githubUrlFor(ORGANIZATION.getValue())) .setGoogleChatSpace(spaceName) .vBuild(); } - void setTravisClient(TravisClient travisClient) { - this.travisClient = travisClient; + /** + * Sets {@link #client} to be used during handling of signals. + * + * @implNote the method is intended to be used as part of the entity configuration + * done through the repository + */ + void setClient(TravisClient client) { + this.client = client; } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java index 21294e01..ddbc8dcc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java @@ -28,7 +28,7 @@ import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.route.EventRouting; -import static io.spine.chatbot.server.github.SpineOrgInitProcess.SPINE_ORGANIZATION; +import static io.spine.chatbot.server.github.SpineOrgInitProcess.ORGANIZATION; import static io.spine.server.route.EventRoute.withId; /** @@ -47,11 +47,11 @@ final class SpineOrgInitRepository @Override protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); - routing.route(SpaceRegistered.class, (event, context) -> withId(SPINE_ORGANIZATION)); + routing.route(SpaceRegistered.class, (event, context) -> withId(ORGANIZATION)); } @Override protected void configure(SpineOrgInitProcess processManager) { - processManager.setTravisClient(travisClient); + processManager.setClient(travisClient); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index d3cc4d8c..0ecedb85 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -30,7 +30,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.SpineOrgInitProcess.SPINE_ORGANIZATION; +import static io.spine.chatbot.server.github.SpineOrgInitProcess.ORGANIZATION; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @DisplayName("SpineOrgInitProcess should") @@ -54,7 +54,7 @@ void registerSpace() { .newBuilder() .addRepositories(repository) .vBuild(); - travisClient().setRepositoriesFor(SPINE_ORGANIZATION.getValue(), repositoriesResponse); + travisClient().setRepositoriesFor(ORGANIZATION.getValue(), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() .setSpace(spaceId) @@ -71,9 +71,9 @@ void settingState() { .newBuilder() .setGoogleChatSpace(spaceId.getValue()) .setInitialized(true) - .setOrganization(SPINE_ORGANIZATION) + .setOrganization(ORGANIZATION) .vBuild(); - context().assertState(SPINE_ORGANIZATION, OrganizationInit.class) + context().assertState(ORGANIZATION, OrganizationInit.class) .isEqualTo(expectedState); } From 90ca1f18da1848671972ff2df197c54964d8c901 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:50:54 +0300 Subject: [PATCH 349/492] Improve wording --- .../main/java/io/spine/chatbot/server/github/package-info.java | 2 +- .../java/io/spine/chatbot/server/google/chat/package-info.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java index d2353159..b2a85844 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java @@ -22,7 +22,7 @@ * This package contains server-side implementation of the GitHub Context. * *

    This package is annotated with {@code BoundedContext} annotation to mark - * entities of this package (and sub-packages if they existed) as parts of the context. + * entities of this package (and sub-packages, if any) as parts of the context. */ @BoundedContext(GitHubContext.GIT_HUB_CONTEXT_NAME) @CheckReturnValue diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java index 049f4d99..8f4e5c3a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java @@ -22,7 +22,7 @@ * This package contains server-side implementation of the Google Chat Context. * *

    This package is annotated with {@code BoundedContext} annotation to mark - * entities of this package (and sub-packages if they existed) as parts of the context. + * entities of this package (and sub-packages, if any) as parts of the context. */ @BoundedContext(GoogleChatContext.GOOGLE_CHAT_CONTEXT_NAME) @CheckReturnValue From acec0d7a01e55dab82f607cdea53f919b904ab39 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:52:02 +0300 Subject: [PATCH 350/492] Use {@code} when the name is already specified in the signature --- .../io/spine/chatbot/server/github/GitHubIdentifier.java | 4 ++-- .../chatbot/server/google/chat/GoogleChatIdentifier.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java index fc7fc029..44a49664 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java @@ -37,7 +37,7 @@ private GitHubIdentifier() { } /** - * Creates a new {@link OrganizationId} out of the specified {@code name}. + * Creates a new {@code OrganizationId} out of the specified {@code name}. */ public static OrganizationId organization(String name) { checkNotEmptyOrBlank(name); @@ -48,7 +48,7 @@ public static OrganizationId organization(String name) { } /** - * Creates a new {@link RepositoryId} out of the specified {@code slug}. + * Creates a new {@code RepositoryId} out of the specified {@code slug}. */ public static RepositoryId repository(String slug) { checkNotEmptyOrBlank(slug); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java index 4fb7fa65..83d0bbb6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java @@ -38,7 +38,7 @@ private GoogleChatIdentifier() { } /** - * Creates a new {@link ThreadId} out of the specified {@code value}. + * Creates a new {@code ThreadId} out of the specified {@code value}. */ public static ThreadId thread(String value) { checkNotEmptyOrBlank(value); @@ -49,7 +49,7 @@ public static ThreadId thread(String value) { } /** - * Creates a new {@link SpaceId} out of the specified {@code value}. + * Creates a new {@code SpaceId} out of the specified {@code value}. */ public static SpaceId space(String value) { checkNotEmptyOrBlank(value); @@ -60,7 +60,7 @@ public static SpaceId space(String value) { } /** - * Creates a new {@link MessageId} out of the specified {@code value}. + * Creates a new {@code MessageId} out of the specified {@code value}. */ public static MessageId message(String value) { checkNotEmptyOrBlank(value); From a5029f1ef3366b80d1b02d9e8e87cfe94a34743e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:53:37 +0300 Subject: [PATCH 351/492] Add missing docs --- .../chatbot/server/google/chat/ThreadChatProcess.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 701a10d7..1aa38179 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -63,7 +63,6 @@ Pair> on(@External BuildFailed e) { var buildState = change.getNewValue(); var repository = e.getRepository(); _info().log("Build for repository `%s` failed.", repository.getValue()); - return processBuildStateUpdate(buildState, repository); } @@ -79,7 +78,6 @@ Pair> on(@External BuildRecovered e) { var buildState = change.getNewValue(); var repository = e.getRepository(); _info().log("Build for repository `%s` recovered.", repository.getValue()); - return processBuildStateUpdate(buildState, repository); } @@ -117,6 +115,12 @@ private boolean shouldCreateThread() { return Messages.isDefault(state().getResource()); } + /** + * Sets {@link #client} to be used during handling of signals. + * + * @implNote the method is intended to be used as part of the entity configuration + * done through the repository + */ void setClient(GoogleChatClient client) { this.client = client; } From 95bccab25425952bcd80987d6637c5f5ce581d48 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:54:02 +0300 Subject: [PATCH 352/492] Use emptyOrBlank check and replace `{@link}` with `{@code}` --- .../spine/chatbot/server/google/chat/ThreadResources.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java index 0084a0cd..e3754057 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadResources.java @@ -22,7 +22,7 @@ import io.spine.chatbot.google.chat.thread.ThreadResource; -import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** * A utility for working with {@link ThreadResource}s. @@ -36,10 +36,10 @@ private ThreadResources() { } /** - * Creates a new {@link ThreadResource} with the specified {@code name}. + * Creates a new {@code ThreadResource} with the specified {@code name}. */ public static ThreadResource threadResource(String name) { - checkNotNull(name); + checkNotEmptyOrBlank(name); return ThreadResource .newBuilder() .setName(name) From 3cfa81be8acc2f3e07c65752bf853842212bdd91 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:54:33 +0300 Subject: [PATCH 353/492] Rename googleChatClient to client --- .../chatbot/server/google/chat/ThreadChatRepository.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index a3559e52..697553cc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -43,10 +43,10 @@ final class ThreadChatRepository extends ProcessManagerRepository { - private final GoogleChatClient googleChatClient; + private final GoogleChatClient client; - ThreadChatRepository(GoogleChatClient googleChatClient) { - this.googleChatClient = googleChatClient; + ThreadChatRepository(GoogleChatClient client) { + this.client = client; } @OverridingMethodsMustInvokeSuper @@ -59,7 +59,7 @@ protected void setupEventRouting(EventRouting routing) { @Override protected void configure(ThreadChatProcess processManager) { - processManager.setClient(googleChatClient); + processManager.setClient(client); } private static class RepositoryEventRoute From b1197da80f748d84e3e9b2687303b81182bff486 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:55:30 +0300 Subject: [PATCH 354/492] Chain routing --- .../chatbot/server/google/chat/ThreadChatRepository.java | 4 ++-- .../io/spine/chatbot/server/google/chat/ThreadRepository.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 697553cc..1c095695 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -53,8 +53,8 @@ final class ThreadChatRepository @Override protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); - routing.route(BuildFailed.class, new RepositoryEventRoute<>()); - routing.route(BuildRecovered.class, new RepositoryEventRoute<>()); + routing.route(BuildFailed.class, new RepositoryEventRoute<>()) + .route(BuildRecovered.class, new RepositoryEventRoute<>()); } @Override diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java index 5defe992..50665445 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadRepository.java @@ -36,7 +36,7 @@ final class ThreadRepository extends AggregateRepository routing) { super.setupEventRouting(routing); - routing.route(ThreadCreated.class, (event, context) -> withId(event.getThread())); - routing.route(MessageCreated.class, (event, context) -> withId(event.getThread())); + routing.route(ThreadCreated.class, (event, context) -> withId(event.getThread())) + .route(MessageCreated.class, (event, context) -> withId(event.getThread())); } } From 0dc48f6d128b89762cef3ef058b65b56352f139b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 08:56:57 +0300 Subject: [PATCH 355/492] Extend from interface --- .../server/google/chat/incoming/SpaceMixin.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java index ed611984..4257ffa6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java @@ -21,25 +21,21 @@ package io.spine.chatbot.server.google.chat.incoming; import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.google.chat.incoming.SpaceOrBuilder; import io.spine.chatbot.google.chat.incoming.SpaceType; /** * Provides utility helpers for the {@link io.spine.chatbot.google.chat.incoming.Space Space} type. */ @GeneratedMixin -public interface SpaceMixin { +public interface SpaceMixin extends SpaceOrBuilder { /** - * Determines whether a space is threaded. + * Determines whether the space is threaded. * - * @return `true` if the space is threaded, `false otherwise + * @return {@code true} if the space is threaded, {@code false} otherwise */ default boolean isThreaded() { return getType() == SpaceType.ROOM; } - - /** - * Returns space type. - */ - SpaceType getType(); } From 3896233f22623d0e1f4112b00db77eee5853ba37 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 10:46:22 +0300 Subject: [PATCH 356/492] Rename `Urls` to `MoreUrls` and drop `urlOfSpec` in favor of `Urls.create` --- .../server/github/RepoBuildProcess.java | 4 +-- .../server/github/SpineOrgInitProcess.java | 8 ++--- .../io/spine/net/{Urls.java => MoreUrls.java} | 34 ++++++++----------- .../github/OrganizationAggregateTest.java | 8 ++--- .../github/RepositoryAggregateTest.java | 4 +-- .../net/{UrlsTest.java => MoreUrlsTest.java} | 21 ++++++------ 6 files changed, 36 insertions(+), 43 deletions(-) rename google-chat-bot/src/main/java/io/spine/net/{Urls.java => MoreUrls.java} (74%) rename google-chat-bot/src/test/java/io/spine/net/{UrlsTest.java => MoreUrlsTest.java} (82%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 04eb8f18..b95f5bd0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -43,7 +43,7 @@ import io.spine.server.tuple.EitherOf3; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.net.Urls.travisBuildUrlFor; +import static io.spine.net.MoreUrls.travisBuildUrlFor; import static io.spine.protobuf.Messages.isDefault; import static io.spine.util.Exceptions.newIllegalStateException; @@ -187,7 +187,7 @@ private static BuildState.Commit from(Commit commit) { .setCommittedAt(commit.getCommittedAt()) .setAuthoredBy(commit.getAuthor() .getName()) - .setCompareUrl(Urls.urlOfSpec(commit.getCompareUrl())) + .setCompareUrl(Urls.create(commit.getCompareUrl())) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 0245217a..e502dc6a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -34,15 +34,15 @@ import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.core.External; import io.spine.logging.Logging; +import io.spine.net.Urls; import io.spine.server.command.Command; import io.spine.server.procman.ProcessManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.net.Urls.githubUrlFor; -import static io.spine.net.Urls.travisUrlFor; -import static io.spine.net.Urls.urlOfSpec; +import static io.spine.net.MoreUrls.githubUrlFor; +import static io.spine.net.MoreUrls.travisUrlFor; /** * Spine organization init process. @@ -112,7 +112,7 @@ private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, Strin .newBuilder() .setId(spineOrgId) .setName("Spine Event Engine") - .setWebsiteUrl(urlOfSpec("https://spine.io/")) + .setWebsiteUrl(Urls.create("https://spine.io/")) .setTravisCiUrl(travisUrlFor(ORGANIZATION.getValue())) .setGithubUrl(githubUrlFor(ORGANIZATION.getValue())) .setGoogleChatSpace(spaceName) diff --git a/google-chat-bot/src/main/java/io/spine/net/Urls.java b/google-chat-bot/src/main/java/io/spine/net/MoreUrls.java similarity index 74% rename from google-chat-bot/src/main/java/io/spine/net/Urls.java rename to google-chat-bot/src/main/java/io/spine/net/MoreUrls.java index 647f482d..ccca1ee8 100644 --- a/google-chat-bot/src/main/java/io/spine/net/Urls.java +++ b/google-chat-bot/src/main/java/io/spine/net/MoreUrls.java @@ -21,12 +21,14 @@ package io.spine.net; import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; +import static io.spine.util.Preconditions2.checkPositive; import static java.lang.String.format; /** - * An utility for working with {@link Url}. + * Static factories for creating project-specific {@link Url}s. */ -public final class Urls { +public final class MoreUrls { private static final String TRAVIS_GITHUB_ENDPOINT = "https://travis-ci.com/github"; private static final String GITHUB = "https://github.com"; @@ -34,26 +36,18 @@ public final class Urls { /** * Prevents instantiation of this utility class. */ - private Urls() { + private MoreUrls() { } /** - * Creates a new {@link Url} out of supplied spec. + * Creates a new Travis CI build URL for a build with the specified {@code buildId} of + * the repository with the specified {@code slug}. */ - public static Url urlOfSpec(String spec) { - checkNotNull(spec); - return Url.newBuilder() - .setSpec(spec) - .vBuild(); - } - - /** - * Creates a new Travis CI build URL. - */ - public static Url travisBuildUrlFor(String repoSlug, long buildId) { - checkNotNull(repoSlug); - var spec = format("%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, repoSlug, buildId); - return urlOfSpec(spec); + public static Url travisBuildUrlFor(String slug, long buildId) { + checkNotEmptyOrBlank(slug); + checkPositive(buildId); + var spec = format("%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, slug, buildId); + return Urls.create(spec); } /** @@ -62,7 +56,7 @@ public static Url travisBuildUrlFor(String repoSlug, long buildId) { public static Url travisUrlFor(String slug) { checkNotNull(slug); var spec = format("%s/%s", TRAVIS_GITHUB_ENDPOINT, slug); - return urlOfSpec(spec); + return Urls.create(spec); } /** @@ -71,6 +65,6 @@ public static Url travisUrlFor(String slug) { public static Url githubUrlFor(String slug) { checkNotNull(slug); var spec = format("%s/%s", GITHUB, slug); - return urlOfSpec(spec); + return Urls.create(spec); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index d72ab482..80968808 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -25,15 +25,15 @@ import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.event.OrganizationRegistered; import io.spine.net.Url; +import io.spine.net.Urls; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.net.Urls.githubUrlFor; -import static io.spine.net.Urls.travisUrlFor; -import static io.spine.net.Urls.urlOfSpec; +import static io.spine.net.MoreUrls.githubUrlFor; +import static io.spine.net.MoreUrls.travisUrlFor; @DisplayName("OrganizationAggregate should") final class OrganizationAggregateTest extends GitHubContextAwareTest { @@ -49,7 +49,7 @@ final class Register { private final Url githubUrl = githubUrlFor(organization.getValue()); private final Url travisCiUrl = travisUrlFor(organization.getValue()); - private final Url websiteUrl = urlOfSpec("https://test-organization.com"); + private final Url websiteUrl = Urls.create("https://test-organization.com"); @BeforeEach void registerOrganization() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 2605364a..5b55829c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -33,8 +33,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.net.Urls.githubUrlFor; -import static io.spine.net.Urls.travisUrlFor; +import static io.spine.net.MoreUrls.githubUrlFor; +import static io.spine.net.MoreUrls.travisUrlFor; @DisplayName("RepositoryAggregate should") final class RepositoryAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java b/google-chat-bot/src/test/java/io/spine/net/MoreUrlsTest.java similarity index 82% rename from google-chat-bot/src/test/java/io/spine/net/UrlsTest.java rename to google-chat-bot/src/test/java/io/spine/net/MoreUrlsTest.java index 09588d9b..d3eda500 100644 --- a/google-chat-bot/src/test/java/io/spine/net/UrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/net/MoreUrlsTest.java @@ -26,18 +26,17 @@ import org.junit.jupiter.api.Test; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.net.Urls.githubUrlFor; -import static io.spine.net.Urls.travisBuildUrlFor; -import static io.spine.net.Urls.travisUrlFor; -import static io.spine.net.Urls.urlOfSpec; +import static io.spine.net.MoreUrls.githubUrlFor; +import static io.spine.net.MoreUrls.travisBuildUrlFor; +import static io.spine.net.MoreUrls.travisUrlFor; -@DisplayName("Urls should") -final class UrlsTest extends UtilityClassTest { +@DisplayName("MoreUrls should") +final class MoreUrlsTest extends UtilityClassTest { private static final String REPO_SLUG = "SpineEventEngine/chat-bot"; - UrlsTest() { - super(Urls.class); + MoreUrlsTest() { + super(MoreUrls.class); } @DisplayName("compose URL for") @@ -48,7 +47,7 @@ final class Compose { @DisplayName("Travis CI repository page") @Test void travisRepo() { - assertThat(travisUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( + assertThat(travisUrlFor(REPO_SLUG)).isEqualTo(Urls.create( "https://travis-ci.com/github/SpineEventEngine/chat-bot" )); } @@ -56,7 +55,7 @@ void travisRepo() { @DisplayName("Travis CI repository build page") @Test void travisBuild() { - assertThat(travisBuildUrlFor(REPO_SLUG, 331)).isEqualTo(urlOfSpec( + assertThat(travisBuildUrlFor(REPO_SLUG, 331)).isEqualTo(Urls.create( "https://travis-ci.com/github/SpineEventEngine/chat-bot/builds/331" )); } @@ -64,7 +63,7 @@ void travisBuild() { @DisplayName("GitHub repository page") @Test void githubRepo() { - assertThat(githubUrlFor(REPO_SLUG)).isEqualTo(urlOfSpec( + assertThat(githubUrlFor(REPO_SLUG)).isEqualTo(Urls.create( "https://github.com/SpineEventEngine/chat-bot" )); } From 05d35a1f3bab55b13173f06579c92a474cd01536 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 10:48:35 +0300 Subject: [PATCH 357/492] Move `MoreUrls` to the `chatbot.url` package --- .../io/spine/chatbot/server/github/RepoBuildProcess.java | 2 +- .../spine/chatbot/server/github/SpineOrgInitProcess.java | 4 ++-- .../java/io/spine/{net => chatbot/url}/MoreUrls.java | 5 ++++- .../java/io/spine/{net => chatbot/url}/package-info.java | 4 ++-- .../chatbot/server/github/OrganizationAggregateTest.java | 4 ++-- .../chatbot/server/github/RepositoryAggregateTest.java | 4 ++-- .../java/io/spine/{net => chatbot/url}/MoreUrlsTest.java | 9 +++++---- 7 files changed, 18 insertions(+), 14 deletions(-) rename google-chat-bot/src/main/java/io/spine/{net => chatbot/url}/MoreUrls.java (96%) rename google-chat-bot/src/main/java/io/spine/{net => chatbot/url}/package-info.java (91%) rename google-chat-bot/src/test/java/io/spine/{net => chatbot/url}/MoreUrlsTest.java (91%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index b95f5bd0..72752d4e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -43,7 +43,7 @@ import io.spine.server.tuple.EitherOf3; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.net.MoreUrls.travisBuildUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisBuildUrlFor; import static io.spine.protobuf.Messages.isDefault; import static io.spine.util.Exceptions.newIllegalStateException; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index e502dc6a..0487d145 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -41,8 +41,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.net.MoreUrls.githubUrlFor; -import static io.spine.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.url.MoreUrls.githubUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisUrlFor; /** * Spine organization init process. diff --git a/google-chat-bot/src/main/java/io/spine/net/MoreUrls.java b/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/net/MoreUrls.java rename to google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java index ccca1ee8..09fd3b4b 100644 --- a/google-chat-bot/src/main/java/io/spine/net/MoreUrls.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java @@ -18,7 +18,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.net; +package io.spine.chatbot.url; + +import io.spine.net.Url; +import io.spine.net.Urls; import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; diff --git a/google-chat-bot/src/main/java/io/spine/net/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/url/package-info.java similarity index 91% rename from google-chat-bot/src/main/java/io/spine/net/package-info.java rename to google-chat-bot/src/main/java/io/spine/chatbot/url/package-info.java index 456c6290..d12cebc3 100644 --- a/google-chat-bot/src/main/java/io/spine/net/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/url/package-info.java @@ -19,11 +19,11 @@ */ /** - * This package contains utilities for working with network-related messages. + * This package contains utilities for working with {@link io.spine.net.Url URL}s. */ @CheckReturnValue @ParametersAreNonnullByDefault -package io.spine.net; +package io.spine.chatbot.url; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 80968808..0d178bf3 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -32,8 +32,8 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.net.MoreUrls.githubUrlFor; -import static io.spine.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.url.MoreUrls.githubUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisUrlFor; @DisplayName("OrganizationAggregate should") final class OrganizationAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 5b55829c..b3356304 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -33,8 +33,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.net.MoreUrls.githubUrlFor; -import static io.spine.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.url.MoreUrls.githubUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisUrlFor; @DisplayName("RepositoryAggregate should") final class RepositoryAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/net/MoreUrlsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java similarity index 91% rename from google-chat-bot/src/test/java/io/spine/net/MoreUrlsTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java index d3eda500..3245064f 100644 --- a/google-chat-bot/src/test/java/io/spine/net/MoreUrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java @@ -18,17 +18,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.net; +package io.spine.chatbot.url; +import io.spine.net.Urls; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.net.MoreUrls.githubUrlFor; -import static io.spine.net.MoreUrls.travisBuildUrlFor; -import static io.spine.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.url.MoreUrls.githubUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisBuildUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisUrlFor; @DisplayName("MoreUrls should") final class MoreUrlsTest extends UtilityClassTest { From 79939459059ecd42abba3c63df0aafea1ac85612 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 10:51:54 +0300 Subject: [PATCH 358/492] Inline check --- .../src/main/java/io/spine/chatbot/url/MoreUrls.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java b/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java index 09fd3b4b..0d2ea164 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java @@ -48,8 +48,7 @@ private MoreUrls() { */ public static Url travisBuildUrlFor(String slug, long buildId) { checkNotEmptyOrBlank(slug); - checkPositive(buildId); - var spec = format("%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, slug, buildId); + var spec = format("%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, slug, checkPositive(buildId)); return Urls.create(spec); } From 4972afaa3b2e1124b321a03129d371910d65c8ab Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 10:54:26 +0300 Subject: [PATCH 359/492] Use compact entity option notation --- .../src/main/proto/spine/chatbot/github/organization.proto | 3 +-- .../main/proto/spine/chatbot/github/organization_init.proto | 3 +-- .../proto/spine/chatbot/github/organization_repositories.proto | 3 +-- .../src/main/proto/spine/chatbot/github/repository.proto | 3 +-- .../src/main/proto/spine/chatbot/github/repository_build.proto | 3 +-- .../src/main/proto/spine/chatbot/google/chat/space.proto | 3 +-- .../src/main/proto/spine/chatbot/google/chat/thread.proto | 3 +-- 7 files changed, 7 insertions(+), 14 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index c847ece0..09ca7746 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -36,8 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub organization. message Organization { - option (entity).kind = AGGREGATE; - option (entity).visibility = FULL; + option (entity) = {kind: AGGREGATE visibility: FULL}; OrganizationId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index a899245f..a2565293 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -38,8 +38,7 @@ import "spine/chatbot/github/identifiers.proto"; // for a particular Chat Space. // message OrganizationInit { - option (entity).kind = PROCESS_MANAGER; - option (entity).visibility = FULL; + option (entity) = {kind: PROCESS_MANAGER visibility: FULL}; // The organization for which the initialization is performed. OrganizationId organization = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 2a0d5cda..90583c86 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -34,8 +34,7 @@ import "spine/chatbot/github/identifiers.proto"; // Organization repositories. message OrganizationRepositories { - option (entity).kind = PROJECTION; - option (entity).visibility = FULL; + option (entity) = {kind: PROJECTION visibility: FULL}; OrganizationId organization = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index a937df86..b7a949f0 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -36,8 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub repository. message Repository { - option (entity).kind = AGGREGATE; - option (entity).visibility = FULL; + option (entity) = {kind: AGGREGATE visibility: FULL}; RepositoryId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 7d36c739..cfc90e23 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -39,8 +39,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub repository build process. message RepositoryBuild { - option (entity).kind = PROCESS_MANAGER; - option (entity).visibility = FULL; + option (entity) = {kind: PROCESS_MANAGER visibility: FULL}; RepositoryId repository = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 86fb576b..011453ee 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -34,8 +34,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A room or DM in Chat. message Space { - option (entity).kind = AGGREGATE; - option (entity).visibility = FULL; + option (entity) = {kind: AGGREGATE visibility: FULL}; SpaceId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index ff43f109..c72655c2 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -34,8 +34,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A thread in a room. message Thread { - option (entity).kind = AGGREGATE; - option (entity).visibility = FULL; + option (entity) = {kind: AGGREGATE visibility: FULL}; ThreadId id = 1; From 44b1cea9af4b4d78c9fa14eacf961cd828661e8e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 11:21:39 +0300 Subject: [PATCH 360/492] Extract reusable OrgHeader type --- .../spine/chatbot/RepositoriesController.java | 2 +- .../chatbot/server/github/OrgHeaderAware.java | 74 +++++++++++++++++++ .../server/github/OrganizationAggregate.java | 12 +-- .../server/github/SpineOrgInitProcess.java | 15 ++-- .../spine/chatbot/github/identifiers.proto | 4 +- .../spine/chatbot/github/organization.proto | 28 ++++--- .../github/organization_commands.proto | 20 ++--- .../chatbot/github/organization_events.proto | 18 +---- .../github/OrganizationAggregateTest.java | 27 +++---- 9 files changed, 128 insertions(+), 72 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 87d6b469..d85b685c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -67,7 +67,7 @@ private void checkBuildStatus(Client client, .newBuilder() .setRepository(repository) .setOrganization(organization.getId()) - .setGoogleChatSpace(organization.getGoogleChatSpace()) + .setGoogleChatSpace(organization.googleChatSpace()) .vBuild(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java new file mode 100644 index 00000000..0b61d303 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java @@ -0,0 +1,74 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.github.organization.OrgHeader; +import io.spine.net.Url; + +/** + * Common interface for messages aware of the {@link OrgHeader}. + */ +@GeneratedMixin +public interface OrgHeaderAware { + + /** + * Returns the organization header. + * + * @implNote This method is implemented in the deriving Protobuf messages. + */ + OrgHeader getHeader(); + + /** + * Returns the organization {@code name}. + */ + default String name() { + return getHeader().getName(); + } + + /** + * Returns the organization {@code website}. + */ + default Url website() { + return getHeader().getWebsite(); + } + + /** + * Returns the organization {@code githubProfile}. + */ + default Url githubProfile() { + return getHeader().getGithubProfile(); + } + + /** + * Returns the organization {@code travisProfile}. + */ + default Url travisProfile() { + return getHeader().getTravisProfile(); + } + + /** + * Returns the {@code googleChatSpace} associated with the organization. + */ + default String googleChatSpace() { + return getHeader().getGoogleChatSpace(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java index 9931db20..62df58d2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrganizationAggregate.java @@ -48,20 +48,12 @@ OrganizationRegistered handle(RegisterOrganization c) { return OrganizationRegistered .newBuilder() .setOrganization(c.getId()) - .setGithubUrl(c.getGithubUrl()) - .setName(c.getName()) - .setTravisCiUrl(c.getTravisCiUrl()) - .setWebsiteUrl(c.getWebsiteUrl()) - .setGoogleChatSpace(c.getGoogleChatSpace()) + .setHeader(c.getHeader()) .vBuild(); } @Apply private void on(OrganizationRegistered e) { - builder().setName(e.getName()) - .setGithubUrl(e.getGithubUrl()) - .setTravisCiUrl(e.getTravisCiUrl()) - .setWebsiteUrl(e.getWebsiteUrl()) - .setGoogleChatSpace(e.getGoogleChatSpace()); + builder().setHeader(e.getHeader()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 0487d145..cb4369c7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -28,6 +28,7 @@ import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.github.repository.command.RegisterRepository; @@ -108,15 +109,19 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, String spaceName) { _info().log("Registering `%s` organization.", ORGANIZATION.getValue()); - return RegisterOrganization + var header = OrgHeader .newBuilder() - .setId(spineOrgId) .setName("Spine Event Engine") - .setWebsiteUrl(Urls.create("https://spine.io/")) - .setTravisCiUrl(travisUrlFor(ORGANIZATION.getValue())) - .setGithubUrl(githubUrlFor(ORGANIZATION.getValue())) + .setWebsite(Urls.create("https://spine.io/")) + .setTravisProfile(travisUrlFor(ORGANIZATION.getValue())) + .setGithubProfile(githubUrlFor(ORGANIZATION.getValue())) .setGoogleChatSpace(spaceName) .vBuild(); + return RegisterOrganization + .newBuilder() + .setId(spineOrgId) + .setHeader(header) + .vBuild(); } /** diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto index 395393b5..9b28ac42 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/identifiers.proto @@ -33,14 +33,14 @@ option java_generate_equals_and_hash = true; // GitHub organization ID. message OrganizationId { - // Name of the GitHub organization. + // The name of the GitHub organization. string value = 1 [(required) = true]; } // GitHub repository ID. message RepositoryId { - // Slug of the repository. + // The repository slug. // // E.g. `SpineEventEngine/base`. The slug is used as a human-friendly unique identifier. // diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index 09ca7746..a66e3068 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -37,21 +37,29 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub organization. message Organization { option (entity) = {kind: AGGREGATE visibility: FULL}; + option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; OrganizationId id = 1; - // Name of the GitHub organization. - string name = 2; + // The organization header. + OrgHeader header = 2; +} + +// The GitHub organization header. +message OrgHeader { + + // The name of the GitHub organization. + string name = 1 [(required) = true]; - // URL of the official organization-related website. - spine.net.Url website_url = 3; + // The URL of the official organization-related website. + spine.net.Url website = 2; - // URL of the organization GitHub profile. - spine.net.Url github_url = 4; + // The URL of the organization GitHub profile. + spine.net.Url github_profile = 3 [(required) = true]; - // URL of the organization Travis CI profile. - spine.net.Url travis_ci_url = 5; + // The URL of the organization Travis CI profile. + spine.net.Url travis_profile = 4 [(required) = true]; - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 6; + // The name of the Google Chat space associated with the organization. + string google_chat_space = 5 [(required) = true, (pattern).regex = "spaces/.+"]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 28266364..90388ce6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -33,24 +33,14 @@ option java_generate_equals_and_hash = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/organization.proto"; -// An organization registration command. +// A request to register an organization. message RegisterOrganization { + option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; OrganizationId id = 1 [(required) = true]; - // Name of the GitHub organization. - string name = 2 [(required) = true]; - - // URL of the official organization-related website. - spine.net.Url website_url = 3; - - // URL of the organization GitHub profile. - spine.net.Url github_url = 4 [(required) = true]; - - // URL of the organization Travis CI profile. - spine.net.Url travis_ci_url = 5 [(required) = true]; - - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 6 [(required) = true, (pattern).regex = "spaces/.+"]; + // The organization header. + OrgHeader header = 2; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index a4c51ef4..3522ded3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -33,24 +33,14 @@ option java_generate_equals_and_hash = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/organization.proto"; // An organization is registered. message OrganizationRegistered { + option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; OrganizationId organization = 1 [(required) = true]; - // Name of the GitHub organization. - string name = 2 [(required) = true]; - - // URL of the official organization-related website. - spine.net.Url website_url = 3; - - // URL of the organization GitHub profile. - spine.net.Url github_url = 4 [(required) = true]; - - // URL of the organization Travis CI profile. - spine.net.Url travis_ci_url = 5 [(required) = true]; - - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 6 [(required) = true, (pattern).regex = "spaces/.+"]; + // The organization header. + OrgHeader header = 2; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 0d178bf3..1e2fe23b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.github; import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.event.OrganizationRegistered; @@ -50,17 +51,21 @@ final class Register { private final Url githubUrl = githubUrlFor(organization.getValue()); private final Url travisCiUrl = travisUrlFor(organization.getValue()); private final Url websiteUrl = Urls.create("https://test-organization.com"); + private final OrgHeader header = OrgHeader + .newBuilder() + .setGithubProfile(githubUrl) + .setTravisProfile(travisCiUrl) + .setWebsite(websiteUrl) + .setName(orgName) + .setGoogleChatSpace(googleChatSpace) + .vBuild(); @BeforeEach void registerOrganization() { var registerOrganization = RegisterOrganization .newBuilder() .setId(organization) - .setGithubUrl(githubUrl) - .setTravisCiUrl(travisCiUrl) - .setWebsiteUrl(websiteUrl) - .setName(orgName) - .setGoogleChatSpace(googleChatSpace) + .setHeader(header) .vBuild(); context().receivesCommand(registerOrganization); } @@ -71,11 +76,7 @@ void producingEvent() { var organizationRegistered = OrganizationRegistered .newBuilder() .setOrganization(organization) - .setGithubUrl(githubUrl) - .setTravisCiUrl(travisCiUrl) - .setWebsiteUrl(websiteUrl) - .setName(orgName) - .setGoogleChatSpace(googleChatSpace) + .setHeader(header) .vBuild(); context().assertEvent(organizationRegistered); } @@ -86,11 +87,7 @@ void settingState() { var expectedState = Organization .newBuilder() .setId(organization) - .setGithubUrl(githubUrl) - .setTravisCiUrl(travisCiUrl) - .setWebsiteUrl(websiteUrl) - .setName(orgName) - .setGoogleChatSpace(googleChatSpace) + .setHeader(header) .vBuild(); context().assertState(organization, Organization.class) .isEqualTo(expectedState); From 45754cb49b1bc3aa3a53e246e51969d7f3a01785 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 12:09:18 +0300 Subject: [PATCH 361/492] Extract reusable RepoHeader type --- .../spine/chatbot/RepositoriesController.java | 2 +- .../api/google/chat/BuildStateUpdates.java | 16 ++--- .../chatbot/api/google/chat/GoogleChat.java | 11 +-- .../api/google/chat/GoogleChatClient.java | 6 +- .../server/github/BuildStateMixin.java | 50 +++++++------- .../chatbot/server/github/OrgHeaderAware.java | 7 +- .../server/github/OrgReposRepository.java | 4 +- .../server/github/RepoBuildProcess.java | 25 +++---- .../server/github/RepoHeaderAware.java | 68 +++++++++++++++++++ .../server/github/RepositoryAggregate.java | 15 ++-- .../server/github/SpineOrgInitProcess.java | 29 ++++---- .../server/google/chat/ThreadChatProcess.java | 17 +++-- .../spine/chatbot/github/organization.proto | 5 +- .../github/organization_commands.proto | 4 +- .../chatbot/github/organization_events.proto | 4 +- .../chatbot/github/organization_init.proto | 5 +- .../github/organization_init_commands.proto | 5 +- .../spine/chatbot/github/repository.proto | 23 ++++--- .../chatbot/github/repository_build.proto | 62 ++++++++--------- .../github/repository_build_commands.proto | 5 +- .../github/repository_build_events.proto | 6 +- .../chatbot/github/repository_commands.proto | 21 ++---- .../chatbot/github/repository_events.proto | 17 ++--- .../google/chat/InMemoryGoogleChatClient.java | 4 +- .../server/github/RepoBuildProcessTest.java | 16 ++--- .../github/RepositoryAggregateTest.java | 25 ++++--- 26 files changed, 254 insertions(+), 198 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index d85b685c..2c9eacc7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -67,7 +67,7 @@ private void checkBuildStatus(Client client, .newBuilder() .setRepository(repository) .setOrganization(organization.getId()) - .setGoogleChatSpace(organization.googleChatSpace()) + .setSpace(organization.space()) .vBuild(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index 848a9521..c66c3cbb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -27,7 +27,7 @@ import com.google.api.services.chat.v1.model.Thread; import com.google.api.services.chat.v1.model.WidgetMarkup; import com.google.common.collect.ImmutableList; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.thread.ThreadResource; import static com.google.common.base.Preconditions.checkNotNull; @@ -39,7 +39,7 @@ import static io.spine.validate.Validate.checkValid; /** - * A utility class that creates {@link BuildState} update messages. + * A utility class that creates {@link Build} update messages. */ final class BuildStateUpdates { @@ -55,12 +55,12 @@ private BuildStateUpdates() { } /** - * Creates a new {@link BuildState} update message from the supplied state and thread. + * Creates a new {@link Build} update message from the supplied state and thread. * *

    If the thread has no name set, assumes that the update message should be * sent to a new thread. */ - static Message buildStateMessage(BuildState build, ThreadResource thread) { + static Message buildStateMessage(Build build, ThreadResource thread) { checkValid(build); checkNotNull(thread); var headerIcon = build.failed() ? FAILURE_ICON : SUCCESS_ICON; @@ -79,7 +79,7 @@ static Message buildStateMessage(BuildState build, ThreadResource thread) { return message; } - private static Section commitSection(BuildState build) { + private static Section commitSection(Build build) { var commit = build.getLastCommit(); var commitInfo = String.format( "Authored by %s at %s.", commit.getAuthoredBy(), commit.getCommittedAt() @@ -93,7 +93,7 @@ private static Section commitSection(BuildState build) { return section; } - private static Section actions(BuildState build) { + private static Section actions(Build build) { var commit = build.getLastCommit(); var actionButtons = new WidgetMarkup().setButtons(ImmutableList.of( linkButton("Build", build.getTravisCiUrl()), @@ -102,11 +102,11 @@ private static Section actions(BuildState build) { return sectionWithWidget(actionButtons); } - private static Section buildStateSection(BuildState build) { + private static Section buildStateSection(Build build) { return sectionWithWidget(buildStateWidget(build)); } - private static WidgetMarkup buildStateWidget(BuildState build) { + private static WidgetMarkup buildStateWidget(Build build) { var keyValue = new KeyValue() .setTopLabel("Build No.") .setContent(build.getNumber()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 596a116c..420cf395 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -29,7 +29,8 @@ import com.google.auth.oauth2.GoogleCredentials; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.api.google.secret.Secrets; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.logging.Logging; @@ -68,13 +69,13 @@ public static GoogleChatClient newInstance() { } @Override - public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread) { + public Message sendBuildStateUpdate(Build buildState, ThreadResource thread) { var repoSlug = buildState.getRepositorySlug(); var debug = _debug(); debug.log("Building state update message for repository `%s`.", repoSlug); var message = buildStateMessage(buildState, thread); debug.log("Sending state update message for repository `%s`.", repoSlug); - var result = sendMessage(buildState.getGoogleChatSpace(), message); + var result = sendMessage(buildState.getSpace(), message); debug.log( "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", result.getName(), repoSlug, result.getThread() @@ -84,12 +85,12 @@ public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread } @CanIgnoreReturnValue - private Message sendMessage(String space, Message message) { + private Message sendMessage(SpaceId space, Message message) { try { return chat .spaces() .messages() - .create(space, message) + .create(space.getValue(), message) .execute(); } catch (IOException e) { _error().withCause(e) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java index 792721ce..7196ea82 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java @@ -21,7 +21,7 @@ package io.spine.chatbot.api.google.chat; import com.google.api.services.chat.v1.model.Message; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.thread.ThreadResource; /** @@ -33,11 +33,11 @@ public interface GoogleChatClient { /** - * Sends {@link BuildState} status message to a related space and thread. + * Sends {@link Build} status message to a related space and thread. * *

    If the {@code thread} has no name specified the message is sent to a new thread. * * @return a sent message */ - Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread); + Message sendBuildStateUpdate(Build buildState, ThreadResource thread); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java index e89f9805..731e1bc0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -21,39 +21,39 @@ package io.spine.chatbot.server.github; import io.spine.annotation.GeneratedMixin; -import io.spine.chatbot.github.repository.build.BuildState; -import io.spine.chatbot.github.repository.build.BuildStateOrBuilder; -import io.spine.chatbot.github.repository.build.BuildStateStatusChange; +import io.spine.chatbot.github.repository.build.Build; +import io.spine.chatbot.github.repository.build.BuildOrBuilder; +import io.spine.chatbot.github.repository.build.BuildStateChange; import java.util.EnumSet; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.chatbot.github.repository.build.BuildState.State.PASSED; -import static io.spine.chatbot.github.repository.build.BuildState.State.S_UNKNOWN; -import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.FAILED; -import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.RECOVERED; -import static io.spine.chatbot.github.repository.build.BuildStateStatusChange.STABLE; +import static io.spine.chatbot.github.repository.build.Build.State.BS_UNKNOWN; +import static io.spine.chatbot.github.repository.build.Build.State.PASSED; +import static io.spine.chatbot.github.repository.build.BuildStateChange.Type.FAILED; +import static io.spine.chatbot.github.repository.build.BuildStateChange.Type.RECOVERED; +import static io.spine.chatbot.github.repository.build.BuildStateChange.Type.STABLE; import static io.spine.util.Exceptions.newIllegalArgumentException; import static io.spine.util.Exceptions.newIllegalStateException; /** - * Augments {@link BuildState} with useful methods. + * Augments {@link Build} with useful methods. */ @GeneratedMixin -public interface BuildStateMixin extends BuildStateOrBuilder { +public interface BuildStateMixin extends BuildOrBuilder { /** * Determines whether the build is failed. * * @return `true` if the build is failed, `false` otherwise - * @see #failed(BuildState.State) + * @see #failed(Build.State) */ default boolean failed() { return failed(getState()); } /** - * Returns a capitalized label of the {@link BuildState.State build state}. + * Returns a capitalized label of the {@link Build.State build state}. */ default String stateLabel() { var state = getState(); @@ -63,12 +63,12 @@ default String stateLabel() { } /** - * Creates an instance of the {@link BuildState.State build state} of out its + * Creates an instance of the {@link Build.State build state} of out its * string representation. */ - static BuildState.State buildStateFrom(String state) { + static Build.State buildStateFrom(String state) { checkNotNull(state); - for (BuildState.State buildState : BuildState.State.values()) { + for (Build.State buildState : Build.State.values()) { if (state.equalsIgnoreCase(buildState.name())) { return buildState; } @@ -79,17 +79,17 @@ static BuildState.State buildStateFrom(String state) { } /** - * Determines the {@link BuildStateStatusChange status chage} of the build comparing to the + * Determines the {@link BuildStateChange state chage} of the build comparing to the * {@code previousState}. * - * @see #statusChange(BuildStateMixin, BuildStateMixin) + * @see #stateChange(BuildStateMixin, BuildStateMixin) */ - default BuildStateStatusChange stateChangeFrom(BuildStateMixin previousState) { - return statusChange(this, previousState); + default BuildStateChange.Type stateChangeFrom(BuildStateMixin previousState) { + return stateChange(this, previousState); } /** - * Determines the {@link BuildStateStatusChange status chage} between build states. + * Determines the {@link BuildStateChange state chage} between build states. * *

    The status is considered: * @@ -101,8 +101,8 @@ default BuildStateStatusChange stateChangeFrom(BuildStateMixin previousState) { * {@code unknown} meaning that there were no previous states or {@code passed} as well. * */ - private static BuildStateStatusChange statusChange(BuildStateMixin newBuildState, - BuildStateMixin previousBuildState) { + private static BuildStateChange.Type stateChange(BuildStateMixin newBuildState, + BuildStateMixin previousBuildState) { var currentState = newBuildState.getState(); var previousState = previousBuildState.getState(); if (newBuildState.failed()) { @@ -111,7 +111,7 @@ private static BuildStateStatusChange statusChange(BuildStateMixin newBuildState if (currentState == PASSED && previousBuildState.failed()) { return RECOVERED; } - if (currentState == PASSED && (previousState == PASSED || previousState == S_UNKNOWN)) { + if (currentState == PASSED && (previousState == PASSED || previousState == BS_UNKNOWN)) { return STABLE; } throw newIllegalStateException( @@ -128,9 +128,9 @@ private static BuildStateStatusChange statusChange(BuildStateMixin newBuildState * * @return {@code true} if the build status is failed, {@code false} otherwise */ - private static boolean failed(BuildState.State state) { + private static boolean failed(Build.State state) { var failedStatuses = EnumSet.of( - BuildState.State.CANCELLED, BuildState.State.FAILED, BuildState.State.ERRORED + Build.State.CANCELLED, Build.State.FAILED, Build.State.ERRORED ); return failedStatuses.contains(state); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java index 0b61d303..f00914b1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java @@ -22,6 +22,7 @@ import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.github.organization.OrgHeader; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.net.Url; /** @@ -66,9 +67,9 @@ default Url travisProfile() { } /** - * Returns the {@code googleChatSpace} associated with the organization. + * Returns the {@code space} associated with the organization. */ - default String googleChatSpace() { - return getHeader().getGoogleChatSpace(); + default SpaceId space() { + return getHeader().getSpace(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java index cf1e884d..61302ed6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposRepository.java @@ -42,8 +42,8 @@ final class OrgReposRepository protected void setupEventRouting(EventRouting routing) { super.setupEventRouting(routing); routing.route(RepositoryRegistered.class, (event, context) -> - isNotDefault(event.getOrganization()) - ? withId(event.getOrganization()) + isNotDefault(event.organization()) + ? withId(event.organization()) : noTargets()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 72752d4e..282a089b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -28,7 +28,7 @@ import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; @@ -36,6 +36,7 @@ import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildSucceededAgain; import io.spine.chatbot.github.repository.build.rejection.NoBuildsFound; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.logging.Logging; import io.spine.net.Urls; import io.spine.server.command.Assign; @@ -89,14 +90,14 @@ EitherOf3 handle(CheckReposito .setRepository(repository) .build(); } - var buildState = buildStateFrom(branchBuild, c.getGoogleChatSpace()); + var build = buildFrom(branchBuild, c.getSpace()); builder().setLastStatusCheck(Time.currentTime()) - .setRepositoryBuildState(buildState.getState()) - .setBuildState(buildState); + .setBuild(build) + .setCurrentState(build.getState()); var stateChange = BuildStateChange .newBuilder() - .setPreviousValue(state().getBuildState()) - .setNewValue(buildState) + .setPreviousValue(state().getBuild()) + .setNewValue(build) .vBuild(); var result = determineOutcome(repository, stateChange); return result; @@ -114,7 +115,7 @@ EitherOf3 handle(CheckReposito return onRecovered(repository, stateChange); case STABLE: return onStable(repository, stateChange); - case BSC_UNKNOWN: + case BSCT_UNKNOWN: case UNRECOGNIZED: default: throw newIllegalStateException( @@ -159,15 +160,15 @@ EitherOf3 handle(CheckReposito } @VisibleForTesting - static BuildState buildStateFrom(RepoBranchBuildResponse branchBuild, String space) { + static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { var branchBuildName = branchBuild.getName(); var slug = branchBuild.getRepository() .getSlug(); var build = branchBuild.getLastBuild(); - return BuildState + return Build .newBuilder() .setNumber(build.getNumber()) - .setGoogleChatSpace(space) + .setSpace(space) .setState(BuildStateMixin.buildStateFrom(build.getState())) .setPreviousState(BuildStateMixin.buildStateFrom(build.getPreviousState())) .setBranch(branchBuildName) @@ -179,8 +180,8 @@ static BuildState buildStateFrom(RepoBranchBuildResponse branchBuild, String spa .vBuild(); } - private static BuildState.Commit from(Commit commit) { - return BuildState.Commit + private static Build.Commit from(Commit commit) { + return Build.Commit .newBuilder() .setSha(commit.getSha()) .setMessage(commit.getMessage()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java new file mode 100644 index 00000000..54f44062 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java @@ -0,0 +1,68 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.repository.RepoHeader; +import io.spine.net.Url; + +/** + * Common interface for messages aware of the {@link RepoHeader}. + */ +@GeneratedMixin +public interface RepoHeaderAware { + + /** + * Returns the repository header. + * + * @implNote This method is implemented in the deriving Protobuf messages. + */ + RepoHeader getHeader(); + + /** + * Returns the repository {@code name}. + */ + default String name() { + return getHeader().getName(); + } + + /** + * Returns the repository {@code githubProfile}. + */ + default Url githubProfile() { + return getHeader().getGithubProfile(); + } + + /** + * Returns the repository {@code travisProfile}. + */ + default Url travisProfile() { + return getHeader().getTravisProfile(); + } + + /** + * Returns the organization associated with the repository. + */ + default OrganizationId organization() { + return getHeader().getOrganization(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java index 47d81703..15cf5639 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAggregate.java @@ -34,8 +34,7 @@ * *

    The ChatBot watches for the repository build status. */ -final class RepositoryAggregate - extends Aggregate +final class RepositoryAggregate extends Aggregate implements Logging { /** @@ -43,24 +42,18 @@ final class RepositoryAggregate */ @Assign RepositoryRegistered handle(RegisterRepository c) { - var repository = c.getRepository(); + var repository = c.getId(); _info().log("Registering repository `%s`.", repository.getValue()); var result = RepositoryRegistered .newBuilder() .setRepository(repository) - .setName(c.getName()) - .setGithubUrl(c.getGithubUrl()) - .setTravisCiUrl(c.getTravisCiUrl()) - .setOrganization(c.getOrganization()) + .setHeader(c.getHeader()) .vBuild(); return result; } @Apply private void on(RepositoryRegistered e) { - builder().setName(e.getName()) - .setGithubUrl(e.getGithubUrl()) - .setTravisCiUrl(e.getTravisCiUrl()) - .setOrganization(e.getOrganization()); + builder().setHeader(e.getHeader()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index cb4369c7..af94eb16 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -31,7 +31,9 @@ import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; +import io.spine.chatbot.github.repository.RepoHeader; import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.core.External; import io.spine.logging.Logging; @@ -78,8 +80,7 @@ Iterable on(@External SpaceRegistered e) { _info().log("Spine organization is already initialized. Skipping the process."); return ImmutableSet.of(); } - var space = e.getSpace() - .getValue(); + var space = e.getSpace(); _info().log("Starting Spine organization initialization process in space `%s`.", space); var commands = ImmutableSet.builder(); commands.add(registerOrgCommand(ORGANIZATION, space)); @@ -89,25 +90,29 @@ Iterable on(@External SpaceRegistered e) { .filter(repository -> WATCHED_REPOS.contains(repository.getName())) .map(repository -> registerRepoCommand(repository, ORGANIZATION)) .forEach(commands::add); - builder().setGoogleChatSpace(space) + builder().setSpace(space) .setInitialized(true); return commands.build(); } - private RegisterRepository registerRepoCommand(Repository repo, OrganizationId orgId) { + private RegisterRepository registerRepoCommand(Repository repo, OrganizationId org) { var slug = repo.getSlug(); _info().log("Registering `%s` repository.", slug); - return RegisterRepository + var header = RepoHeader .newBuilder() - .setRepository(repository(slug)) - .setOrganization(orgId) - .setGithubUrl(githubUrlFor(slug)) + .setOrganization(org) + .setGithubProfile(githubUrlFor(slug)) .setName(repo.getName()) - .setTravisCiUrl(travisUrlFor(slug)) + .setTravisProfile(travisUrlFor(slug)) + .vBuild(); + return RegisterRepository + .newBuilder() + .setId(repository(slug)) + .setHeader(header) .vBuild(); } - private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, String spaceName) { + private RegisterOrganization registerOrgCommand(OrganizationId spineOrg, SpaceId space) { _info().log("Registering `%s` organization.", ORGANIZATION.getValue()); var header = OrgHeader .newBuilder() @@ -115,11 +120,11 @@ private RegisterOrganization registerOrgCommand(OrganizationId spineOrgId, Strin .setWebsite(Urls.create("https://spine.io/")) .setTravisProfile(travisUrlFor(ORGANIZATION.getValue())) .setGithubProfile(githubUrlFor(ORGANIZATION.getValue())) - .setGoogleChatSpace(spaceName) + .setSpace(space) .vBuild(); return RegisterOrganization .newBuilder() - .setId(spineOrgId) + .setId(spineOrg) .setHeader(header) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 1aa38179..22c478ba 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -23,7 +23,7 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.google.chat.ThreadId; @@ -41,7 +41,6 @@ import java.util.Optional; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @@ -60,10 +59,10 @@ final class ThreadChatProcess extends ProcessManager> on(@External BuildFailed e) { var change = e.getChange(); - var buildState = change.getNewValue(); + var build = change.getNewValue(); var repository = e.getRepository(); _info().log("Build for repository `%s` failed.", repository.getValue()); - return processBuildStateUpdate(buildState, repository); + return processBuildStateUpdate(build, repository); } /** @@ -75,18 +74,18 @@ Pair> on(@External BuildFailed e) { @React Pair> on(@External BuildRecovered e) { var change = e.getChange(); - var buildState = change.getNewValue(); + var build = change.getNewValue(); var repository = e.getRepository(); _info().log("Build for repository `%s` recovered.", repository.getValue()); - return processBuildStateUpdate(buildState, repository); + return processBuildStateUpdate(build, repository); } private Pair> - processBuildStateUpdate(BuildState buildState, RepositoryId repository) { - var sentMessage = client.sendBuildStateUpdate(buildState, state().getResource()); + processBuildStateUpdate(Build build, RepositoryId repository) { + var sentMessage = client.sendBuildStateUpdate(build, state().getResource()); var message = message(sentMessage.getName()); var thread = thread(repository.getValue()); - var space = space(buildState.getGoogleChatSpace()); + var space = build.getSpace(); var messageCreated = MessageCreated .newBuilder() .setMessage(message) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index a66e3068..97284a92 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -33,6 +33,7 @@ option java_generate_equals_and_hash = true; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/google/chat/identifiers.proto"; // A GitHub organization. message Organization { @@ -60,6 +61,6 @@ message OrgHeader { // The URL of the organization Travis CI profile. spine.net.Url travis_profile = 4 [(required) = true]; - // The name of the Google Chat space associated with the organization. - string google_chat_space = 5 [(required) = true, (pattern).regex = "spaces/.+"]; + // The Google Chat space associated with the organization. + spine.chatbot.google.chat.SpaceId space = 5 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 90388ce6..7d6ebba3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -30,8 +30,6 @@ option java_outer_classname = "OrganizationCommandsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; import "spine/chatbot/github/organization.proto"; @@ -42,5 +40,5 @@ message RegisterOrganization { OrganizationId id = 1 [(required) = true]; // The organization header. - OrgHeader header = 2; + OrgHeader header = 2 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index 3522ded3..d15cacc3 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -30,8 +30,6 @@ option java_outer_classname = "OrganizationEventsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; import "spine/chatbot/github/organization.proto"; @@ -42,5 +40,5 @@ message OrganizationRegistered { OrganizationId organization = 1 [(required) = true]; // The organization header. - OrgHeader header = 2; + OrgHeader header = 2 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index a2565293..1ad2e408 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -31,6 +31,7 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/google/chat/identifiers.proto"; // The initialization process of the default watched organization resources. // @@ -43,8 +44,8 @@ message OrganizationInit { // The organization for which the initialization is performed. OrganizationId organization = 1; - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 2; + // The Google Chat space associated with the organization. + spine.chatbot.google.chat.SpaceId space = 2; // Determines whether the organization resources are already initialized. bool initialized = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index c97792b7..9e65068f 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -31,6 +31,7 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/google/chat/identifiers.proto"; // Initialize watched organization resources command. message InitializeOrganization { @@ -38,6 +39,6 @@ message InitializeOrganization { // The organization to perform initialization for. OrganizationId organization = 1 [(required) = true]; - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 2 [(required) = true, (pattern).regex = "spaces/.+"]; + // The Google Chat space associated with the organization. + spine.chatbot.google.chat.SpaceId space = 2 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index b7a949f0..d3d592ad 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -31,24 +31,31 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; // A GitHub repository. message Repository { option (entity) = {kind: AGGREGATE visibility: FULL}; + option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; RepositoryId id = 1; - // Name of the repository. - string name = 2; + // The repository header. + RepoHeader header = 2; +} + +// The GitHub repository header. +message RepoHeader { + + // The name of the repository. + string name = 1 [(required) = true]; - // GitHub URL of the repository. - spine.net.Url github_url = 3; + // The URL of the repository GitHub profile. + spine.net.Url github_profile = 2 [(required) = true]; - // Travis CI URL of the repository. - spine.net.Url travis_ci_url = 4; + // The URL of the Travis CI profile. + spine.net.Url travis_profile = 3 [(required) = true]; // The organization repository is related to, if any. - OrganizationId organization = 5; + OrganizationId organization = 4; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index cfc90e23..2fb56e7a 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -34,45 +34,27 @@ option java_generate_equals_and_hash = true; import "google/protobuf/timestamp.proto"; import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/google/chat/identifiers.proto"; -// A GitHub repository build process. +// A build process of a GitHub repository. message RepositoryBuild { option (entity) = {kind: PROCESS_MANAGER visibility: FULL}; RepositoryId repository = 1; - // Time of the last status check. - google.protobuf.Timestamp last_status_check = 2; + // The time of the last status check. + .google.protobuf.Timestamp last_status_check = 2; - // Current state of the build. - BuildState build_state = 3; + // The current state. + Build build = 3; // Current repository build state. - BuildState.State repository_build_state = 4 [(column) = true]; -} - -// The state change status of the build. -enum BuildStateStatusChange { - - BSC_UNKNOWN = 0; - - // The build has failed. - // - // It could be either a build configuration failure or the actual code build issue. - // - FAILED = 1; - - // The build has recovered from the failed state. - RECOVERED = 2; - - // The build is stable. - STABLE = 3; + Build.State current_state = 4 [(column) = true]; } // State of the build for a repository branch. -message BuildState { +message Build { option (is).java_type = "io.spine.chatbot.server.github.BuildStateMixin"; @@ -90,7 +72,7 @@ message BuildState { // The build state. enum State { - S_UNKNOWN = 0; + BS_UNKNOWN = 0; // The build is created. CREATED = 1; @@ -151,16 +133,34 @@ message BuildState { // The repository slug the build is associated with. string repository_slug = 8; - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 9 [(pattern).regex = "spaces/.+"]; + // The Google Chat space associated with the organization. + spine.chatbot.google.chat.SpaceId space = 9 [(required) = true, (validate) = true]; } // Definition of a change in a `build_state` field. message BuildStateChange { // The value of the field that's changing. - BuildState previous_value = 1; + Build previous_value = 1; // The new value of the field. - BuildState new_value = 2 [(required) = true]; + Build new_value = 2 [(required) = true]; + + // The type of the build state change. + enum Type { + + BSCT_UNKNOWN = 0; + + // The build has failed. + // + // It could be either a build configuration failure or the actual code build issue. + // + FAILED = 1; + + // The build has recovered from the failed state. + RECOVERED = 2; + + // The build is stable. + STABLE = 3; + } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index 35e7a336..c3afa662 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -31,6 +31,7 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/google/chat/identifiers.proto"; // Check repository CI build state command. message CheckRepositoryBuild { @@ -41,6 +42,6 @@ message CheckRepositoryBuild { // The organization the repository belongs to. OrganizationId organization = 2 [(required) = true]; - // Name of the Google Chat space associated with the organization in form `spaces/`. - string google_chat_space = 3 [(required) = true, (pattern).regex = "spaces/.+"]; + // The Google Chat space associated with the organization. + spine.chatbot.google.chat.SpaceId space = 3 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index ccbd73ce..7c818bbe 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -41,7 +41,7 @@ message BuildFailed { RepositoryId repository = 1 [(required) = true]; // The change of the build state. - BuildStateChange change = 2; + BuildStateChange change = 2 [(required) = true]; } // The build has recovered from the failed state. @@ -50,7 +50,7 @@ message BuildRecovered { RepositoryId repository = 1 [(required) = true]; // The change of the build state. - BuildStateChange change = 2; + BuildStateChange change = 2 [(required) = true]; } // The build is stable and passing. @@ -59,7 +59,7 @@ message BuildSucceededAgain { RepositoryId repository = 1 [(required) = true]; // The change of the build state. - BuildStateChange change = 2; + BuildStateChange change = 2 [(required) = true]; } // The build is stable and passing. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 85a2325f..48086b3c 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -30,24 +30,15 @@ option java_outer_classname = "RepositoryCommandsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/repository.proto"; -// Register repository command. +// A request to register a repository. message RegisterRepository { + option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; - RepositoryId repository = 1 [(required) = true]; - - // Name of the repository. - string name = 2 [(required) = true]; - - // GitHub URL of the repository. - spine.net.Url github_url = 3 [(required) = true]; - - // Travis CI URL of the repository. - spine.net.Url travis_ci_url = 4 [(required) = true]; + RepositoryId id = 1 [(required) = true]; - // ID of the organization the repository is related to, if any. - OrganizationId organization = 5; + // The repository header. + RepoHeader header = 2 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index 18316168..e822326f 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -30,24 +30,15 @@ option java_outer_classname = "RepositoryEventsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -import "spine/net/url.proto"; - import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/repository.proto"; // A repository is registered. message RepositoryRegistered { + option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; RepositoryId repository = 1 [(required) = true]; - // Name of the repository. - string name = 2 [(required) = true]; - - // GitHub URL of the repository. - spine.net.Url github_url = 3 [(required) = true]; - - // Travis CI URL of the repository. - spine.net.Url travis_ci_url = 4 [(required) = true]; - - // ID of the organization the repository is related to if any. - OrganizationId organization = 5; + // The repository header. + RepoHeader header = 2 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java index c6edae0b..53cbc156 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java @@ -22,7 +22,7 @@ import com.google.api.services.chat.v1.model.Message; import io.spine.chatbot.api.FailFastAwareClient; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.thread.ThreadResource; import java.util.Map; @@ -56,7 +56,7 @@ public static InMemoryGoogleChatClient lenientClient() { } @Override - public Message sendBuildStateUpdate(BuildState buildState, ThreadResource thread) { + public Message sendBuildStateUpdate(Build buildState, ThreadResource thread) { var stubbedValue = sentMessages.get(buildState.getNumber()); var result = failOrDefault(stubbedValue, buildState.getNumber(), new Message()); return result; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index bc59c2be..abaf9700 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -41,7 +41,7 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.chatbot.server.github.RepoBuildProcess.buildStateFrom; +import static io.spine.chatbot.server.github.RepoBuildProcess.buildFrom; @DisplayName("RepoBuildProcess should") final class RepoBuildProcessTest extends GitHubContextAwareTest { @@ -77,7 +77,7 @@ final class FailedBuild { private final Build build = failedBuild(); private final RepoBranchBuildResponse branchBuild = branchBuildOf(build); - private final BuildState buildState = buildStateFrom(branchBuild, chatSpace); + private final BuildState buildState = buildFrom(branchBuild, chatSpace); @BeforeEach void sendCheckCommand() { @@ -127,12 +127,12 @@ final class RecoveredBuild { private final Build previousBuild = failedBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); - private final BuildState previousBuildState = buildStateFrom(previousBranchBuild, - chatSpace); + private final BuildState previousBuildState = buildFrom(previousBranchBuild, + chatSpace); private final Build newBuild = passingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); - private final BuildState newBuildState = buildStateFrom(newBranchBuild, chatSpace); + private final BuildState newBuildState = buildFrom(newBranchBuild, chatSpace); @BeforeEach void sendCheckCommands() { @@ -193,12 +193,12 @@ final class StableBuild { private final Build previousBuild = passingBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); - private final BuildState previousBuildState = buildStateFrom(previousBranchBuild, - chatSpace); + private final BuildState previousBuildState = buildFrom(previousBranchBuild, + chatSpace); private final Build newBuild = nextPassingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); - private final BuildState newBuildState = buildStateFrom(newBranchBuild, chatSpace); + private final BuildState newBuildState = buildFrom(newBranchBuild, chatSpace); @BeforeEach void sendCheckCommands() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index b3356304..932bb778 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -22,6 +22,7 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.repository.RepoHeader; import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.github.repository.event.RepositoryRegistered; @@ -52,16 +53,20 @@ final class Register { private final Url githubUrl = githubUrlFor(REPO_SLUG); private final Url travisCiUrl = travisUrlFor(REPO_SLUG); + private final RepoHeader header = RepoHeader + .newBuilder() + .setGithubProfile(githubUrl) + .setTravisProfile(travisCiUrl) + .setName(REPO_NAME) + .setOrganization(organization) + .vBuild(); @BeforeEach void registerRepository() { var registerRepository = RegisterRepository .newBuilder() - .setRepository(repository) - .setGithubUrl(githubUrl) - .setTravisCiUrl(travisCiUrl) - .setName(REPO_NAME) - .setOrganization(organization) + .setId(repository) + .setHeader(header) .vBuild(); context().receivesCommand(registerRepository); } @@ -72,10 +77,7 @@ void producingEvent() { var repositoryRegistered = RepositoryRegistered .newBuilder() .setRepository(repository) - .setGithubUrl(githubUrl) - .setTravisCiUrl(travisCiUrl) - .setName(REPO_NAME) - .setOrganization(organization) + .setHeader(header) .vBuild(); context().assertEvent(repositoryRegistered); } @@ -86,10 +88,7 @@ void settingState() { var expectedState = Repository .newBuilder() .setId(repository) - .setGithubUrl(githubUrl) - .setTravisCiUrl(travisCiUrl) - .setName(REPO_NAME) - .setOrganization(organization) + .setHeader(header) .vBuild(); context().assertState(repository, Repository.class) .isEqualTo(expectedState); From 948ccea6a3b71ac1f0f32b8f1db739fa03e42fe1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 12:11:20 +0300 Subject: [PATCH 362/492] Improve wording --- .../main/proto/spine/chatbot/google/chat/chat_events.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto index 00beebe3..3874d5f9 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat_events.proto @@ -38,10 +38,10 @@ message MessageCreated { MessageId message = 1 [(required) = true]; - // ID of the space within which the message is created. + // The space within which the message is created. SpaceId space = 2 [(required) = true]; - // ID of the thread within which the message is created if created in a threaded space. + // The thread within which the message is created, if created in a threaded space. ThreadId thread = 3; } @@ -53,6 +53,6 @@ message ThreadCreated { // Chat thread. ThreadResource resource = 2 [(required) = true]; - // ID of the space within with the thread is available. + // The space within with the thread is available. SpaceId space = 3 [(required) = true]; } From 0e1aaa65b0b480fbd075f39f7beba441e11ff2a0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 12:11:29 +0300 Subject: [PATCH 363/492] Add missing validations --- .../chatbot/google/chat/incoming/incoming_chat_events.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto index c9ea3892..ac41acda 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto @@ -20,7 +20,7 @@ message BotAddedToSpace { SpaceId space = 1 [(required) = true]; // The actual chat event message. - ChatEvent event = 2; + ChatEvent event = 2 [(required) = true]; } // The ChatBot is removed from the Chat space. @@ -30,7 +30,7 @@ message BotRemovedFromSpace { SpaceId space = 1 [(required) = true]; // The actual chat event message. - ChatEvent event = 2; + ChatEvent event = 2 [(required) = true]; } // The ChatBot received a new incoming Chat message. @@ -40,5 +40,5 @@ message MessageReceived { MessageId message = 1 [(required) = true]; // The actual chat event message. - ChatEvent event = 2; + ChatEvent event = 2 [(required) = true]; } From a07daf7707ca653679a3fc7a847f26be64f084d5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 12:30:47 +0300 Subject: [PATCH 364/492] Extract `ChatEventReceived` domain event that should be used instead `ChatEvent`, while `ChatEvent` is Google Chat-specific data type. --- .../chatbot/IncomingEventsController.java | 7 +- .../google/chat/IncomingEventsHandler.java | 4 +- .../chat/incoming/incoming_chat_events.proto | 7 ++ .../incoming/incoming_chat_messages.proto | 22 +++--- .../github/OrganizationAggregateTest.java | 7 +- .../server/github/RepoBuildProcessTest.java | 73 ++++++++++--------- .../github/SpineOrgInitProcessTest.java | 2 +- .../chat/IncomingEventsHandlerTest.java | 26 ++++--- .../google/chat/ThreadChatProcessTest.java | 9 +-- 9 files changed, 90 insertions(+), 67 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index b92d2bb5..b7aa3abc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -27,6 +27,7 @@ import io.micronaut.runtime.event.annotation.EventListener; import io.spine.chatbot.google.chat.incoming.ChatEvent; import io.spine.chatbot.google.chat.incoming.User; +import io.spine.chatbot.google.chat.incoming.event.ChatEventReceived; import io.spine.core.UserId; import io.spine.json.Json; import io.spine.logging.Logging; @@ -57,7 +58,11 @@ String on(@Body PubsubPushRequest pushNotification) { _debug().log("Received a new chat event: %s", chatEventJson); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); var actor = eventActor(chatEvent.getUser()); - INCOMING_EVENTS.emittedEvent(chatEvent, actor); + var chatEventReceived = ChatEventReceived + .newBuilder() + .setEvent(chatEvent) + .vBuild(); + INCOMING_EVENTS.emittedEvent(chatEventReceived, actor); return "OK"; } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index e3e77f3a..2f00c04c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -23,6 +23,7 @@ import io.spine.chatbot.google.chat.incoming.ChatEvent; import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import io.spine.chatbot.google.chat.incoming.event.BotRemovedFromSpace; +import io.spine.chatbot.google.chat.incoming.event.ChatEventReceived; import io.spine.chatbot.google.chat.incoming.event.MessageReceived; import io.spine.core.External; import io.spine.logging.Logging; @@ -58,7 +59,8 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin */ @React EitherOf4 - on(@External ChatEvent chatEvent) { + on(@External ChatEventReceived e) { + var chatEvent = e.getEvent(); switch (chatEvent.getType()) { case MESSAGE: _info().log("New user message received."); diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto index ac41acda..1ce41363 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_events.proto @@ -13,6 +13,13 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/incoming/incoming_chat_messages.proto"; +// A new event received from the Chat. +message ChatEventReceived { + + // The received event. + ChatEvent event = 1 [(required) = true]; +} + // The ChatBot is added to a Chat space. message BotAddedToSpace { diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index b35e07e6..9c19171d 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -45,9 +45,7 @@ option java_generate_equals_and_hash = true; // message ChatEvent { - option (is).java_type = "io.spine.base.EventMessage"; - - // type of the event + // The type of the event EventType type = 1 [(required) = true]; // The timestamp indicating when the event was dispatched. @@ -81,7 +79,7 @@ message ChatEvent { // message Message { - // Resource name, in the form "spaces/*/messages/*". + // The resource name, in the form "spaces/*/messages/*". string name = 1 [(required) = true, (pattern).regex = "spaces/.+/messages/.+"]; // The user who created the message. @@ -90,11 +88,11 @@ message Message { // The time at which the message was created in Hangouts Chat server. string create_time = 3; - // Plain-text body of the message. + // The plain-text body of the message. string text = 4; - // Plain-text body of the message with all bot mentions stripped out. - string argumentText = 5; + // The plain-text body of the message with all bot mentions stripped out. + string argument_text = 5; // The thread the message belongs to. Thread thread = 6; @@ -112,10 +110,10 @@ message Message { // Annotation metadata of the message message Annotation { - // Length of the substring in the plain-text message body this annotation corresponds to. + // The length of the substring in the plain-text message body this annotation corresponds to. uint32 length = 1; - // Start index (0-based, inclusive) in the plain-text message body this annotation + // The start index (0-based, inclusive) in the plain-text message body this annotation // corresponds to. // uint32 start_index = 2; @@ -133,7 +131,7 @@ message Message { User user = 2; } - // The type of this annotation. + // The type of the annotation. string type = 4; } } @@ -147,7 +145,7 @@ message Space { option (is).java_type = "io.spine.chatbot.server.google.chat.incoming.SpaceMixin"; - // Resource name of the space, in the form "spaces/*". + // The resource name of the space, in the form "spaces/*". string name = 1 [(required) = true, (pattern).regex = "spaces/.+"]; // The display name (only if the space is a room). @@ -164,7 +162,7 @@ message Space { // message User { - // Resource name, in the format "users/*". + // The resource name, in the format "users/*". string name = 1 [(required) = true, (pattern).regex = "users/.+"]; // The user's display name. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 1e2fe23b..6c2bb32e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -25,6 +25,7 @@ import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.event.OrganizationRegistered; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.net.Url; import io.spine.net.Urls; import org.junit.jupiter.api.BeforeEach; @@ -33,6 +34,7 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.GitHubIdentifier.organization; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; @@ -44,20 +46,21 @@ final class OrganizationAggregateTest extends GitHubContextAwareTest { final class Register { private static final String orgName = "Test Organization"; - private static final String googleChatSpace = "spaces/qwdp123ttQ"; + private final SpaceId googleChatSpace = space("spaces/qwdp123ttQ"); private final OrganizationId organization = organization("TestOrganization"); private final Url githubUrl = githubUrlFor(organization.getValue()); private final Url travisCiUrl = travisUrlFor(organization.getValue()); private final Url websiteUrl = Urls.create("https://test-organization.com"); + private final OrgHeader header = OrgHeader .newBuilder() .setGithubProfile(githubUrl) .setTravisProfile(travisCiUrl) .setWebsite(websiteUrl) .setName(orgName) - .setGoogleChatSpace(googleChatSpace) + .setSpace(googleChatSpace) .vBuild(); @BeforeEach diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index abaf9700..878de09b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -20,13 +20,12 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.Build; import io.spine.chatbot.api.travis.Commit; import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; @@ -34,6 +33,7 @@ import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.github.repository.build.event.BuildSucceededAgain; import io.spine.chatbot.github.repository.build.rejection.RepositoryBuildRejections; +import io.spine.chatbot.google.chat.SpaceId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -42,13 +42,14 @@ import static io.spine.chatbot.server.github.GitHubIdentifier.organization; import static io.spine.chatbot.server.github.GitHubIdentifier.repository; import static io.spine.chatbot.server.github.RepoBuildProcess.buildFrom; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @DisplayName("RepoBuildProcess should") final class RepoBuildProcessTest extends GitHubContextAwareTest { private static final OrganizationId org = organization("SpineEventEngine"); private static final RepositoryId repository = repository("SpineEventEngine/web"); - private static final String chatSpace = "spaces/1245wrq"; + private static final SpaceId chatSpace = space("spaces/1245wrq"); @Test @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") @@ -59,7 +60,7 @@ void throwNoBuildsFoundRejection() { .newBuilder() .setRepository(repository) .setOrganization(org) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .vBuild(); context().receivesCommand(checkRepoBuild); @@ -75,9 +76,9 @@ void throwNoBuildsFoundRejection() { @DisplayName("handle build failure") final class FailedBuild { - private final Build build = failedBuild(); + private final io.spine.chatbot.api.travis.Build build = failedBuild(); private final RepoBranchBuildResponse branchBuild = branchBuildOf(build); - private final BuildState buildState = buildFrom(branchBuild, chatSpace); + private final Build buildState = buildFrom(branchBuild, chatSpace); @BeforeEach void sendCheckCommand() { @@ -85,7 +86,7 @@ void sendCheckCommand() { var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoBuild); @@ -112,8 +113,8 @@ void settingState() { var expectedState = RepositoryBuild .newBuilder() .setRepository(repository) - .setBuildState(buildState) - .setRepositoryBuildState(buildState.getState()) + .setBuild(buildState) + .setCurrentState(buildState.getState()) .vBuild(); context().assertState(repository, RepositoryBuild.class) .isEqualTo(expectedState); @@ -125,14 +126,14 @@ void settingState() { @DisplayName("handle build recovery") final class RecoveredBuild { - private final Build previousBuild = failedBuild(); + private final io.spine.chatbot.api.travis.Build previousBuild = failedBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); - private final BuildState previousBuildState = buildFrom(previousBranchBuild, - chatSpace); + private final Build previousBuildState = buildFrom(previousBranchBuild, + chatSpace); - private final Build newBuild = passingBuild(); + private final io.spine.chatbot.api.travis.Build newBuild = passingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); - private final BuildState newBuildState = buildFrom(newBranchBuild, chatSpace); + private final Build newBuildState = buildFrom(newBranchBuild, chatSpace); @BeforeEach void sendCheckCommands() { @@ -140,7 +141,7 @@ void sendCheckCommands() { var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); @@ -148,7 +149,7 @@ void sendCheckCommands() { var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); @@ -176,8 +177,8 @@ void settingState() { var expectedState = RepositoryBuild .newBuilder() .setRepository(repository) - .setBuildState(newBuildState) - .setRepositoryBuildState(newBuildState.getState()) + .setBuild(newBuildState) + .setCurrentState(newBuildState.getState()) .vBuild(); context().assertState(repository, RepositoryBuild.class) .isEqualTo(expectedState); @@ -189,16 +190,16 @@ void settingState() { @DisplayName("handle stable builds") final class StableBuild { - private final Build initialFailedBuild = failedBuild(); + private final io.spine.chatbot.api.travis.Build initialFailedBuild = failedBuild(); - private final Build previousBuild = passingBuild(); + private final io.spine.chatbot.api.travis.Build previousBuild = passingBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); - private final BuildState previousBuildState = buildFrom(previousBranchBuild, - chatSpace); + private final Build previousBuildState = buildFrom(previousBranchBuild, + chatSpace); - private final Build newBuild = nextPassingBuild(); + private final io.spine.chatbot.api.travis.Build newBuild = nextPassingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); - private final BuildState newBuildState = buildFrom(newBranchBuild, chatSpace); + private final Build newBuildState = buildFrom(newBranchBuild, chatSpace); @BeforeEach void sendCheckCommands() { @@ -206,7 +207,7 @@ void sendCheckCommands() { var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); @@ -214,7 +215,7 @@ void sendCheckCommands() { var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); @@ -222,7 +223,7 @@ void sendCheckCommands() { var checkRepoStable = CheckRepositoryBuild .newBuilder() .setRepository(repository) - .setGoogleChatSpace(chatSpace) + .setSpace(chatSpace) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoStable); @@ -250,15 +251,15 @@ void settingState() { var expectedState = RepositoryBuild .newBuilder() .setRepository(repository) - .setBuildState(newBuildState) - .setRepositoryBuildState(newBuildState.getState()) + .setBuild(newBuildState) + .setCurrentState(newBuildState.getState()) .vBuild(); context().assertState(repository, RepositoryBuild.class) .isEqualTo(expectedState); } } - private static RepoBranchBuildResponse branchBuildOf(Build build) { + private static RepoBranchBuildResponse branchBuildOf(io.spine.chatbot.api.travis.Build build) { return RepoBranchBuildResponse .newBuilder() .setLastBuild(build) @@ -268,8 +269,8 @@ private static RepoBranchBuildResponse branchBuildOf(Build build) { .buildPartial(); } - private static Build passingBuild() { - return Build + private static io.spine.chatbot.api.travis.Build passingBuild() { + return io.spine.chatbot.api.travis.Build .newBuilder() .setId(123153L) .setNumber("42") @@ -280,8 +281,8 @@ private static Build passingBuild() { .buildPartial(); } - private static Build nextPassingBuild() { - return Build + private static io.spine.chatbot.api.travis.Build nextPassingBuild() { + return io.spine.chatbot.api.travis.Build .newBuilder() .setId(123154L) .setNumber("43") @@ -292,8 +293,8 @@ private static Build nextPassingBuild() { .buildPartial(); } - private static Build failedBuild() { - return Build + private static io.spine.chatbot.api.travis.Build failedBuild() { + return io.spine.chatbot.api.travis.Build .newBuilder() .setId(123152L) .setNumber("41") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 0ecedb85..a0d7d867 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -69,7 +69,7 @@ void registerSpace() { void settingState() { var expectedState = OrganizationInit .newBuilder() - .setGoogleChatSpace(spaceId.getValue()) + .setSpace(spaceId) .setInitialized(true) .setOrganization(ORGANIZATION) .vBuild(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index c68387b1..07075096 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -29,6 +29,7 @@ import io.spine.chatbot.google.chat.incoming.User; import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import io.spine.chatbot.google.chat.incoming.event.BotRemovedFromSpace; +import io.spine.chatbot.google.chat.incoming.event.ChatEventReceived; import io.spine.chatbot.google.chat.incoming.event.MessageReceived; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -49,14 +50,14 @@ final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { @DisplayName("add bot to a space") void addBot() { // given - var chatEvent = chatEventOfType(ADDED_TO_SPACE); + var chatEventReceived = chatEventReceived(ADDED_TO_SPACE); var botAddedToSpace = BotAddedToSpace .newBuilder() - .setEvent(chatEvent) + .setEvent(chatEventReceived.getEvent()) .setSpace(spaceId) .vBuild(); // when - context().receivesExternalEvent(chatEvent); + context().receivesExternalEvent(chatEventReceived); // then context().assertEvent(botAddedToSpace); } @@ -65,14 +66,14 @@ void addBot() { @DisplayName("remove bot from the space") void removeBot() { // given - var chatEvent = chatEventOfType(REMOVED_FROM_SPACE); + var chatEventReceived = chatEventReceived(REMOVED_FROM_SPACE); var botRemovedFromSpace = BotRemovedFromSpace .newBuilder() - .setEvent(chatEvent) + .setEvent(chatEventReceived.getEvent()) .setSpace(spaceId) .vBuild(); // when - context().receivesExternalEvent(chatEvent); + context().receivesExternalEvent(chatEventReceived); // then context().assertEvent(botRemovedFromSpace); } @@ -81,18 +82,25 @@ void removeBot() { @DisplayName("receive incoming message") void receiveIncomingMessage() { // given - var chatEvent = chatEventOfType(MESSAGE); + var chatEventReceived = chatEventReceived(MESSAGE); var messageReceived = MessageReceived .newBuilder() - .setEvent(chatEvent) + .setEvent(chatEventReceived.getEvent()) .setMessage(messageId) .vBuild(); // when - context().receivesExternalEvent(chatEvent); + context().receivesExternalEvent(chatEventReceived); // then context().assertEvent(messageReceived); } + private static ChatEventReceived chatEventReceived(EventType type) { + return ChatEventReceived + .newBuilder() + .setEvent(chatEventOfType(type)) + .vBuild(); + } + private static ChatEvent chatEventOfType(EventType type) { return ChatEvent .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index b87e0fb2..0dfbfeb6 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -24,7 +24,7 @@ import com.google.api.services.chat.v1.model.Thread; import io.spine.base.EventMessage; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.repository.build.BuildState; +import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; @@ -81,12 +81,11 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, private abstract static class BuildStateChanged extends GoogleChatContextAwareTest { - private static final String googleChatSpace = "spaces/1241pjwqe"; private static final String buildNumber = "551"; private final RepositoryId repository = repository("SpineEventEngine/money"); private final ThreadId thread = thread(repository.getValue()); - private final SpaceId space = space(googleChatSpace); + private final SpaceId space = space("spaces/1241pjwqe"); private final Thread newThread = new Thread().setName("spaces/1241pjwqe/threads/k12d1o2r1"); private final Message sentMessage = new Message() @@ -96,9 +95,9 @@ private abstract static class BuildStateChanged extends GoogleChatContextAwareTe @BeforeEach void receiveBuildStateChange() { googleChatClient().setMessageForBuildStatusUpdate(buildNumber, sentMessage); - var newBuildState = BuildState + var newBuildState = Build .newBuilder() - .setGoogleChatSpace(googleChatSpace) + .setSpace(space) .setNumber(buildNumber) .vBuild(); var buildStateChange = BuildStateChange From aa3d2ed846a6cd799f2353d090986a2190689753 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 13:24:30 +0300 Subject: [PATCH 365/492] Extract SpaceHeader type --- .../server/google/chat/SpaceAggregate.java | 17 +++--- .../server/google/chat/SpaceHeaderAware.java | 59 +++++++++++++++++++ .../spine/chatbot/google/chat/space.proto | 16 +++-- .../chatbot/google/chat/space_commands.proto | 12 ++-- .../chatbot/google/chat/space_events.proto | 12 ++-- .../spine/chatbot/google/chat/thread.proto | 4 +- .../github/SpineOrgInitProcessTest.java | 15 +++-- .../google/chat/SpaceAggregateTest.java | 24 ++++---- 8 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index a685c50f..25ebe5ea 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.google.chat; import io.spine.chatbot.google.chat.Space; +import io.spine.chatbot.google.chat.SpaceHeader; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; @@ -48,12 +49,16 @@ SpaceRegistered on(BotAddedToSpace e) { var displayName = space.getDisplayName(); var spaceId = e.getSpace(); _info().log("Registering space `%s` (`%s`).", displayName, spaceId.getValue()); - return SpaceRegistered + var header = SpaceHeader .newBuilder() - .setSpace(spaceId) .setDisplayName(displayName) .setThreaded(space.isThreaded()) .vBuild(); + return SpaceRegistered + .newBuilder() + .setSpace(spaceId) + .setHeader(header) + .vBuild(); } /** @@ -66,17 +71,13 @@ SpaceRegistered handle(RegisterSpace c) { var result = SpaceRegistered .newBuilder() .setSpace(space) - .setSingleUserBotDm(c.getSingleUserBotDm()) - .setThreaded(c.getThreaded()) - .setDisplayName(c.getDisplayName()) + .setHeader(c.getHeader()) .vBuild(); return result; } @Apply private void on(SpaceRegistered e) { - builder().setDisplayName(e.getDisplayName()) - .setSingleUserBotDm(e.getSingleUserBotDm()) - .setThreaded(e.getThreaded()); + builder().setHeader(e.getHeader()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java new file mode 100644 index 00000000..2589ba08 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java @@ -0,0 +1,59 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.google.chat.SpaceHeader; + +/** + * Common interface for messages aware of the {@link SpaceHeader}. + */ +@GeneratedMixin +public interface SpaceHeaderAware { + + /** + * Returns the space header. + * + * @implNote This method is implemented in the deriving Protobuf messages. + */ + SpaceHeader getHeader(); + + /** + * Determines whether a space is a Direct Message (DM) between a bot and a human. + */ + default boolean directMessage() { + return getHeader().getSingleUserBotDm(); + } + + /** + * Determines whether the messages are threaded in the space. + */ + default boolean isThreaded() { + return getHeader().getThreaded(); + } + + /** + * Returns the display name of the space. + */ + default String displayName() { + return getHeader().getDisplayName(); + } +} diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 011453ee..0160f772 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -35,15 +35,23 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A room or DM in Chat. message Space { option (entity) = {kind: AGGREGATE visibility: FULL}; + option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; SpaceId id = 1; + // The space header. + SpaceHeader header = 2; +} + +// The Chat space header. +message SpaceHeader { + // Whether the space is a DM between a bot and a single human. - bool single_user_bot_dm = 3; + bool single_user_bot_dm = 1; // Whether the messages are threaded in this space. - bool threaded = 4; + bool threaded = 2; // The display name (only if the space is a room). - string display_name = 5; -} + string display_name = 3; +} \ No newline at end of file diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 55396926..d53e5ff6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -31,18 +31,14 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/space.proto"; // Register Chat space command. message RegisterSpace { + option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; SpaceId id = 1 [(required) = true]; - // Whether the space is a DM between a bot and a single human. - bool single_user_bot_dm = 3; - - // Whether the messages are threaded in this space. - bool threaded = 4; - - // The display name (only if the space is a room). - string display_name = 5; + // The space header. + SpaceHeader header = 2 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto index abd5a294..8e4c1e47 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -31,18 +31,14 @@ option java_multiple_files = true; option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/space.proto"; // A new Chat space registered. message SpaceRegistered { + option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; SpaceId space = 1 [(required) = true]; - // Whether the space is a DM between a bot and a single human. - bool single_user_bot_dm = 3; - - // Whether the messages are threaded in this space. - bool threaded = 4; - - // The display name (only if the space is a room). - string display_name = 5; + // The space header. + SpaceHeader header = 2 [(required) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index c72655c2..e692b8bf 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -38,7 +38,7 @@ message Thread { ThreadId id = 1; - // Resource name of the thread. + // The resource name of the thread. ThreadResource resource = 2; // The space within with the thread is available. @@ -51,6 +51,6 @@ message Thread { // Chat Thread resource. message ThreadResource { - // Resource name of the thread, in the form `spaces//threads/`. + // The resource name of the thread, in the form `spaces//threads/`. string name = 1 [(required) = true, (pattern).regex = "spaces/.+/threads/.+"]; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index a0d7d867..4e0c470e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -23,6 +23,7 @@ import io.spine.chatbot.api.travis.RepositoriesResponse; import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.organization.init.OrganizationInit; +import io.spine.chatbot.google.chat.SpaceHeader; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; import org.junit.jupiter.api.BeforeEach; @@ -40,13 +41,18 @@ final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @DisplayName("perform initialization of watched spine resources") final class Init { - private final SpaceId spaceId = space("spaces/qjwrp1441"); + private final SpaceId space = space("spaces/qjwrp1441"); private final Repository repository = Repository .newBuilder() .setId(123312L) .setName("time") .setSlug("SpineEventEngine/time") .vBuild(); + private final SpaceHeader header = SpaceHeader + .newBuilder() + .setThreaded(true) + .setDisplayName("Test Space") + .vBuild(); @BeforeEach void registerSpace() { @@ -57,9 +63,8 @@ void registerSpace() { travisClient().setRepositoriesFor(ORGANIZATION.getValue(), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() - .setSpace(spaceId) - .setDisplayName("Test space") - .setThreaded(true) + .setSpace(space) + .setHeader(header) .vBuild(); context().receivesExternalEvent(spaceRegistered); } @@ -69,7 +74,7 @@ void registerSpace() { void settingState() { var expectedState = OrganizationInit .newBuilder() - .setSpace(spaceId) + .setSpace(space) .setInitialized(true) .setOrganization(ORGANIZATION) .vBuild(); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 58fd7697..e8851bac 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.google.chat; import io.spine.chatbot.google.chat.Space; +import io.spine.chatbot.google.chat.SpaceHeader; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.command.RegisterSpace; import io.spine.chatbot.google.chat.event.SpaceRegistered; @@ -40,7 +41,11 @@ final class SpaceAggregateTest extends GoogleChatContextAwareTest { private static final SpaceId SPACE = space("spaces/poqwdpQ21"); - private static final String DISPLAY_NAME = "Spine Developers"; + private final SpaceHeader HEADER = SpaceHeader + .newBuilder() + .setThreaded(true) + .setDisplayName("Spine Developers") + .vBuild(); @Nested @DisplayName("register a space") @@ -51,8 +56,7 @@ void registerSpace() { var registerSpace = RegisterSpace .newBuilder() .setId(SPACE) - .setThreaded(true) - .setDisplayName(DISPLAY_NAME) + .setHeader(HEADER) .vBuild(); context().receivesCommand(registerSpace); } @@ -63,8 +67,7 @@ void producingEvent() { var spaceRegistered = SpaceRegistered .newBuilder() .setSpace(SPACE) - .setDisplayName(DISPLAY_NAME) - .setThreaded(true) + .setHeader(HEADER) .vBuild(); context().assertEvent(spaceRegistered); } @@ -75,8 +78,7 @@ void settingState() { var expectedState = Space .newBuilder() .setId(SPACE) - .setThreaded(true) - .setDisplayName(DISPLAY_NAME) + .setHeader(HEADER) .vBuild(); context().assertState(SPACE, Space.class) .isEqualTo(expectedState); @@ -111,8 +113,7 @@ void producingEvent() { var spaceRegistered = SpaceRegistered .newBuilder() .setSpace(SPACE) - .setDisplayName(DISPLAY_NAME) - .setThreaded(true) + .setHeader(HEADER) .vBuild(); context().assertEvent(spaceRegistered); } @@ -123,8 +124,7 @@ void settingState() { var expectedState = Space .newBuilder() .setId(SPACE) - .setThreaded(true) - .setDisplayName(DISPLAY_NAME) + .setHeader(HEADER) .vBuild(); context().assertState(SPACE, Space.class) .isEqualTo(expectedState); @@ -134,7 +134,7 @@ private io.spine.chatbot.google.chat.incoming.Space chatSpace() { return io.spine.chatbot.google.chat.incoming.Space .newBuilder() .setName(SPACE.getValue()) - .setDisplayName(DISPLAY_NAME) + .setDisplayName(HEADER.getDisplayName()) .setType(ROOM) .vBuild(); } From fc19f9db01dfe5d7a6a42eb5219068dad0237d7e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 13:30:01 +0300 Subject: [PATCH 366/492] Improve wording and extract nested types --- .../incoming/incoming_chat_messages.proto | 60 +++++++++---------- .../proto/spine/chatbot/travis/travis.proto | 16 ++--- .../server/github/RepoBuildProcessTest.java | 7 ++- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 9c19171d..67ddc0ac 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -20,12 +20,12 @@ syntax = "proto3"; -// This file contains the proto definitions that conforms to the +// This file contains the proto definitions that conform to the // // event formats of the Hangouts Chat. // -// We use the defined protos instead of hand-crafting the dedicated classes and managing -// the JSON conversion manually. +// The layout of types and fields make them compatible with the Travis JSON output. +// This way we don't have to create custom conversion. // package spine.chatbot.google.chat.incoming; @@ -97,43 +97,43 @@ message Message { // The thread the message belongs to. Thread thread = 6; - // A thread in Chat. - message Thread { - - // Resource name, in the form "spaces/*/threads/*". - string name = 1 [(required) = true, (pattern).regex = "spaces/.+/threads/.+"]; - } - // Annotations associated with the text in this message. repeated Annotation annotations = 7; +} + +// Annotation metadata of the message. +message Annotation { - // Annotation metadata of the message - message Annotation { + // The length of the substring in the plain-text message body this annotation corresponds to. + uint32 length = 1; - // The length of the substring in the plain-text message body this annotation corresponds to. - uint32 length = 1; + // The start index (0-based, inclusive) in the plain-text message body this annotation + // corresponds to. + // + uint32 start_index = 2; + + // The metadata of user mention. + UserMention user_mention = 3; - // The start index (0-based, inclusive) in the plain-text message body this annotation - // corresponds to. - // - uint32 start_index = 2; + // The type of the annotation. + string type = 4; +} - // The metadata of user mention. - UserMention user_mention = 3; +// Annotation metadata for user mentions (@). +message UserMention { - // Annotation metadata for user mentions (@). - message UserMention { + // The type of user mention. + string type = 1; - // The type of user mention. - string type = 1; + // The user mentioned. + User user = 2; +} - // The user mentioned. - User user = 2; - } +// A thread in Chat. +message Thread { - // The type of the annotation. - string type = 4; - } + // Resource name, in the form "spaces/*/threads/*". + string name = 1 [(required) = true, (pattern).regex = "spaces/.+/threads/.+"]; } // A room or DM in Chat. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 448f69f2..64d52f2e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -20,11 +20,11 @@ syntax = "proto3"; -// This file contains the proto definitions that conforms to the +// This file contains the proto definitions that conform to the // Travis CI API v3 data types. // -// We use the defined protos instead of hand-crafting the dedicated classes and managing -// the JSON conversion manually. +// The layout of types and fields make them compatible with the Travis JSON output. +// This way we don't have to create custom conversion. // package spine.chatbot.travis; @@ -110,13 +110,13 @@ message Commit { // Commit author. Author author = 7; +} - // Git commit author information. - message Author { +// Git commit author information. +message Author { - // Git name of the commit author. - string name = 1; - } + // Git name of the commit author. + string name = 1; } // Minimal Travis CI build representation. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 878de09b..f610e183 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.github; +import io.spine.chatbot.api.travis.Author; import io.spine.chatbot.api.travis.Commit; import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.api.travis.Repository; @@ -307,7 +308,7 @@ private static io.spine.chatbot.api.travis.Build failedBuild() { private static Commit stableCommit() { var compareUrl = "https://github.com/SpineEventEngine/web/compare/04694f26f24a...afc1b76bf93c"; - var author = Commit.Author + var author = Author .newBuilder() .setName("God") .buildPartial(); @@ -324,7 +325,7 @@ private static Commit stableCommit() { private static Commit luckyCommit() { var compareUrl = "https://github.com/SpineEventEngine/web/compare/6b4d32cadd9c...6b0a31d033a2"; - var author = Commit.Author + var author = Author .newBuilder() .setName("God") .buildPartial(); @@ -341,7 +342,7 @@ private static Commit luckyCommit() { private static Commit fatefulCommit() { var compareUrl = "https://github.com/SpineEventEngine/web/compare/5cbfa7423708...8fcf5d98e50f"; - var author = Commit.Author + var author = Author .newBuilder() .setName("Lucifer") .buildPartial(); From b1e28844ecd5b17a969315091d03f64c1ecf943c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 13:44:57 +0300 Subject: [PATCH 367/492] Create custom DisplayName generator --- .../NarrativeDisplayNameGenerator.java | 41 +++++++++++++++++++ .../test/resources/junit-platform.properties | 20 +++++++++ 2 files changed, 61 insertions(+) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java create mode 100644 google-chat-bot/src/test/resources/junit-platform.properties diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java b/google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java new file mode 100644 index 00000000..be542adb --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java @@ -0,0 +1,41 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot; + +import org.junit.jupiter.api.DisplayNameGenerator; + +/** + * Generates display names for jUnit Jupiter test classes in the narrative BDD-like style. + * + *

    Customizes the display name to be in the form of "{@code `ClassName` should}". + */ +final class NarrativeDisplayNameGenerator extends DisplayNameGenerator.Standard { + + @Override + public String generateDisplayNameForClass(Class testClass) { + var className = super.generateDisplayNameForClass(testClass); + if (className.endsWith("Test")) { + className = className.substring(0, className.lastIndexOf("Test")); + } + var result = String.format("`%s` should", className); + return result; + } +} diff --git a/google-chat-bot/src/test/resources/junit-platform.properties b/google-chat-bot/src/test/resources/junit-platform.properties new file mode 100644 index 00000000..a309d7c4 --- /dev/null +++ b/google-chat-bot/src/test/resources/junit-platform.properties @@ -0,0 +1,20 @@ +# +# Copyright 2020, TeamDev. All rights reserved. +# +# Redistribution and use in source and/or binary forms, with or without +# modification, must retain the above copyright notice and the following +# disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +junit.jupiter.displayname.generator.default=io.spine.chatbot.NarrativeDisplayNameGenerator \ No newline at end of file From 8ee56b65599e822845f1b89f7e86c9f7e04c359f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 13:49:13 +0300 Subject: [PATCH 368/492] Add backticks to test names --- .../java/io/spine/chatbot/BeanFactory.java | 6 +-- .../chatbot/IncomingEventsControllerTest.java | 10 ++--- .../NarrativeDisplayNameGenerator.java | 41 ------------------- ...=> PubsubPushRequestDeserializerTest.java} | 6 +-- .../google/chat/BuildStateUpdatesTest.java | 2 +- .../api/google/chat/ChatWidgetsTest.java | 2 +- .../server/github/BuildStateMixinTest.java | 2 +- .../server/github/GitHubContextTest.java | 2 +- .../server/github/GitHubIdentifierTest.java | 2 +- .../github/OrganizationAggregateTest.java | 2 +- .../server/github/RepoBuildProcessTest.java | 2 +- .../github/RepositoryAggregateTest.java | 2 +- .../github/SpineOrgInitProcessTest.java | 2 +- .../google/chat/GoogleChatContextTest.java | 2 +- .../google/chat/GoogleChatIdentifierTest.java | 2 +- .../chat/IncomingEventsHandlerTest.java | 2 +- .../google/chat/SpaceAggregateTest.java | 2 +- .../google/chat/ThreadAggregateTest.java | 2 +- .../google/chat/ThreadChatProcessTest.java | 2 +- .../google/chat/ThreadResourcesTest.java | 2 +- .../io/spine/chatbot/url/MoreUrlsTest.java | 2 +- .../test/resources/junit-platform.properties | 20 --------- 22 files changed, 26 insertions(+), 91 deletions(-) delete mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java rename google-chat-bot/src/test/java/io/spine/chatbot/{PubsubPushNotificationDeserializerTest.java => PubsubPushRequestDeserializerTest.java} (95%) delete mode 100644 google-chat-bot/src/test/resources/junit-platform.properties diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 7717e146..1beb9c40 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -45,8 +45,8 @@ final class BeanFactory { */ @Singleton @Bean - PubsubPushNotificationDeserializer pubsubDeserializer() { - return new PubsubPushNotificationDeserializer(); + PubsubPushRequestDeserializer pubsubDeserializer() { + return new PubsubPushRequestDeserializer(); } /** @@ -57,7 +57,7 @@ PubsubPushNotificationDeserializer pubsubDeserializer() { * Jackson Deserialization */ @VisibleForTesting - static final class PubsubPushNotificationDeserializer + static final class PubsubPushRequestDeserializer extends JsonDeserializer { /** diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 67913b5f..e7491f48 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -25,7 +25,6 @@ import io.micronaut.http.MediaType; import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; -import io.micronaut.runtime.server.EmbeddedServer; import io.micronaut.test.annotation.MicronautTest; import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; import io.spine.chatbot.api.travis.InMemoryTravisClient; @@ -43,16 +42,13 @@ import static io.spine.chatbot.Application.startServer; import static org.junit.jupiter.api.Assertions.assertEquals; -@DisplayName("IncomingEventsController should") @MicronautTest +@DisplayName("`IncomingEventsController` should") final class IncomingEventsControllerTest { - @Inject - EmbeddedServer server; - @Inject @Client("/") - HttpClient client; + private HttpClient client; @SuppressWarnings("ResultOfMethodCallIgnored") // we're not interested in GRPC server here @BeforeAll @@ -69,7 +65,7 @@ static void setupServer() { } @Test - @DisplayName("receive and decode a pubsub message with Google Chat event") + @DisplayName("receive and decode a Pub/Sub message with Google Chat event") void receiveAndDecode() { var pubsubMessage = PubsubMessage .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java b/google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java deleted file mode 100644 index be542adb..00000000 --- a/google-chat-bot/src/test/java/io/spine/chatbot/NarrativeDisplayNameGenerator.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.chatbot; - -import org.junit.jupiter.api.DisplayNameGenerator; - -/** - * Generates display names for jUnit Jupiter test classes in the narrative BDD-like style. - * - *

    Customizes the display name to be in the form of "{@code `ClassName` should}". - */ -final class NarrativeDisplayNameGenerator extends DisplayNameGenerator.Standard { - - @Override - public String generateDisplayNameForClass(Class testClass) { - var className = super.generateDisplayNameForClass(testClass); - if (className.endsWith("Test")) { - className = className.substring(0, className.lastIndexOf("Test")); - } - var result = String.format("`%s` should", className); - return result; - } -} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java similarity index 95% rename from google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java index d636e034..fe709dc5 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushNotificationDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java @@ -35,14 +35,14 @@ import java.text.ParseException; @MicronautTest -@DisplayName("PubsubPushNotificationDeserializer should") -final class PubsubPushNotificationDeserializerTest { +@DisplayName("`PubsubPushRequestDeserializer` should") +final class PubsubPushRequestDeserializerTest { @Inject private ObjectMapperFactory mapperFactory; @Test - @DisplayName("deserialize Pubsub message") + @DisplayName("deserialize Pub/Sub message") void deserializePubsubMessage() throws JsonProcessingException, ParseException { var pubsubMessage = PubsubMessage diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java index 2edf10ef..78fd1e9b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java @@ -23,7 +23,7 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("BuildStateUpdates should") +@DisplayName("`BuildStateUpdates` should") final class BuildStateUpdatesTest extends UtilityClassTest { BuildStateUpdatesTest() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java index c8451cb4..75e4c633 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java @@ -23,7 +23,7 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("ChatWidgets should") +@DisplayName("`ChatWidgets` should") final class ChatWidgetsTest extends UtilityClassTest { ChatWidgetsTest() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java index 99137963..df581387 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java @@ -26,7 +26,7 @@ import static io.spine.chatbot.server.github.BuildStateMixin.buildStateFrom; import static org.junit.jupiter.api.Assertions.assertThrows; -@DisplayName("BuildStateMixin should") +@DisplayName("`BuildStateMixin` should") final class BuildStateMixinTest { @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java index 77a516a6..b1c7141b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -27,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -@DisplayName("GitHubContext should") +@DisplayName("`GitHubContext` should") final class GitHubContextTest { @Test diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java index c7b1c620..e621aeba 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java @@ -24,7 +24,7 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("GitHubIdentifier should") +@DisplayName("`GitHubIdentifier` should") final class GitHubIdentifierTest extends UtilityClassTest { GitHubIdentifierTest() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 6c2bb32e..a307b5ce 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -38,7 +38,7 @@ import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; -@DisplayName("OrganizationAggregate should") +@DisplayName("`OrganizationAggregate` should") final class OrganizationAggregateTest extends GitHubContextAwareTest { @Nested diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index f610e183..37a5c68b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -45,7 +45,7 @@ import static io.spine.chatbot.server.github.RepoBuildProcess.buildFrom; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; -@DisplayName("RepoBuildProcess should") +@DisplayName("`RepoBuildProcess` should") final class RepoBuildProcessTest extends GitHubContextAwareTest { private static final OrganizationId org = organization("SpineEventEngine"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 932bb778..99c2bddf 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -37,7 +37,7 @@ import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; -@DisplayName("RepositoryAggregate should") +@DisplayName("`RepositoryAggregate` should") final class RepositoryAggregateTest extends GitHubContextAwareTest { @Nested diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 4e0c470e..d69348d1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -34,7 +34,7 @@ import static io.spine.chatbot.server.github.SpineOrgInitProcess.ORGANIZATION; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; -@DisplayName("SpineOrgInitProcess should") +@DisplayName("`SpineOrgInitProcess` should") final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @Nested diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java index abfb176a..47011754 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -27,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -@DisplayName("GoogleChatContext should") +@DisplayName("`GoogleChatContext` should") final class GoogleChatContextTest { @Test diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java index 01ce6f94..1872e71d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java @@ -39,7 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -@DisplayName("GoogleChatIdentifier should") +@DisplayName("`GoogleChatIdentifier` should") final class GoogleChatIdentifierTest extends UtilityClassTest { GoogleChatIdentifierTest() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index 07075096..eccac782 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -40,7 +40,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; -@DisplayName("IncomingEventsHandler should") +@DisplayName("`IncomingEventsHandler` should") final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { private static final SpaceId spaceId = space("spaces/fqeq325661a"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index e8851bac..f77420c4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -37,7 +37,7 @@ import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; -@DisplayName("SpaceAggregate should") +@DisplayName("`SpaceAggregate` should") final class SpaceAggregateTest extends GoogleChatContextAwareTest { private static final SpaceId SPACE = space("spaces/poqwdpQ21"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 0a042304..203970c4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -39,7 +39,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; -@DisplayName("ThreadAggregate should") +@DisplayName("`ThreadAggregate` should") final class ThreadAggregateTest extends GoogleChatContextAwareTest { @Nested diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 0dfbfeb6..daa4c88c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -44,7 +44,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; -@DisplayName("ThreadChatProcess should") +@DisplayName("`ThreadChatProcess` should") final class ThreadChatProcessTest { @SuppressWarnings("ClassCanBeStatic") // nested tests do not work with static classes diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java index 8c7145fb..7c549ad7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadResourcesTest.java @@ -23,7 +23,7 @@ import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("ThreadResources should") +@DisplayName("`ThreadResources` should") final class ThreadResourcesTest extends UtilityClassTest { ThreadResourcesTest() { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java index 3245064f..e08dd459 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java @@ -31,7 +31,7 @@ import static io.spine.chatbot.url.MoreUrls.travisBuildUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; -@DisplayName("MoreUrls should") +@DisplayName("`MoreUrls` should") final class MoreUrlsTest extends UtilityClassTest { private static final String REPO_SLUG = "SpineEventEngine/chat-bot"; diff --git a/google-chat-bot/src/test/resources/junit-platform.properties b/google-chat-bot/src/test/resources/junit-platform.properties deleted file mode 100644 index a309d7c4..00000000 --- a/google-chat-bot/src/test/resources/junit-platform.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright 2020, TeamDev. All rights reserved. -# -# Redistribution and use in source and/or binary forms, with or without -# modification, must retain the above copyright notice and the following -# disclaimer. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -junit.jupiter.displayname.generator.default=io.spine.chatbot.NarrativeDisplayNameGenerator \ No newline at end of file From 5623251b3da4d0afe97982f88cd2029b0516aa19 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:03:02 +0300 Subject: [PATCH 369/492] Use JSON from the resource file --- .../PubsubPushRequestDeserializerTest.java | 27 ++++++++++--------- .../test/resources/pubsub_push_request.json | 10 +++++++ 2 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 google-chat-bot/src/test/resources/pubsub_push_request.json diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java index fe709dc5..c972133b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java @@ -21,6 +21,7 @@ package io.spine.chatbot; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.io.Resources; import com.google.common.truth.extensions.proto.ProtoTruth; import com.google.protobuf.ByteString; import com.google.protobuf.util.Timestamps; @@ -32,8 +33,12 @@ import org.junit.jupiter.api.Test; import javax.inject.Inject; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.text.ParseException; +import static io.spine.util.Exceptions.newIllegalStateException; + @MicronautTest @DisplayName("`PubsubPushRequestDeserializer` should") final class PubsubPushRequestDeserializerTest { @@ -59,21 +64,17 @@ void deserializePubsubMessage() throws JsonProcessingException, ParseException { var mapper = mapperFactory.objectMapper(null, null); - var pushNotification = mapper.readValue(PUSH_NOTIFICATION_JSON, - PubsubPushRequest.class); + var pushNotification = mapper.readValue(pushRequestJson(), PubsubPushRequest.class); ProtoTruth.assertThat(pushNotification) .isEqualTo(expectedResult); } - private static final String PUSH_NOTIFICATION_JSON = "" + - "{\n" + - " \"message\": {\n" + - " \"data\": \"eyJrZXkiOiJ2YWx1ZSJ9\",\n" + - " \"messageId\": \"450292511223766\",\n" + - " \"message_id\": \"450292511223766\",\n" + - " \"publishTime\": \"2020-06-21T20:48:25.908Z\",\n" + - " \"publish_time\": \"2020-06-21T20:48:25.908Z\"\n" + - " },\n" + - " \"subscription\": \"projects/test-project/subscriptions/test-subscription\"\n" + - "}"; + private static String pushRequestJson() { + try { + var resource = Resources.getResource("pubsub_push_request.json"); + return Resources.toString(resource, StandardCharsets.UTF_8); + } catch (IOException e) { + throw newIllegalStateException(e, "Unable to load ChatEvent message JSON definition."); + } + } } diff --git a/google-chat-bot/src/test/resources/pubsub_push_request.json b/google-chat-bot/src/test/resources/pubsub_push_request.json new file mode 100644 index 00000000..af5a0293 --- /dev/null +++ b/google-chat-bot/src/test/resources/pubsub_push_request.json @@ -0,0 +1,10 @@ +{ + "message": { + "data": "eyJrZXkiOiJ2YWx1ZSJ9", + "messageId": "450292511223766", + "message_id": "450292511223766", + "publishTime": "2020-06-21T20:48:25.908Z", + "publish_time": "2020-06-21T20:48:25.908Z" + }, + "subscription": "projects/test-project/subscriptions/test-subscription" +} From 8a02706b15d12dde13c906863173a61c9243f1bb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:03:12 +0300 Subject: [PATCH 370/492] Add Git attributes config --- .gitattributes | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..cac54165 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,65 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. + +# Common formats +*.html text +*.xml text +*.css text +*.scss text +*.js text +*.properties text +*.rtf text +*.yaml text +*.yml text +*.md text +*.json text + +LICENSE text + +# SQL scripts +*.sql text + +# Java sources +*.java text + +# Kotlin sources +*.kt text +*.kts text + +# Python sources +*.py text + +# Gradle build files +*.gradle text + +# Google protocol buffers +*.proto text + +# Miscellaneous +*.rb text +*.http text + +# Declare files that will always have CRLF line endings on checkout. +*.bat text eol=crlf + +# Declare files that will always have LF line endings on checkout. +*.sh text eol=lf +gradlew text eol=lf +pull text eol=lf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.gif binary +*.swf binary +*.jar binary +*.desc binary + +*.scpt binary +*.scssc binary + +# Encoded files +*.enc binary From a23a8c3d6467710b09eb0935c6443a0cab748a0c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:04:57 +0300 Subject: [PATCH 371/492] Improve exception wording --- .../io/spine/chatbot/PubsubPushRequestDeserializerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java index c972133b..870ddd07 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java @@ -74,7 +74,9 @@ private static String pushRequestJson() { var resource = Resources.getResource("pubsub_push_request.json"); return Resources.toString(resource, StandardCharsets.UTF_8); } catch (IOException e) { - throw newIllegalStateException(e, "Unable to load ChatEvent message JSON definition."); + throw newIllegalStateException( + e, "Unable to load PubsubPushRequest message JSON definition." + ); } } } From 9109d3b96751488940525af0715084b208940363 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:05:14 +0300 Subject: [PATCH 372/492] Load ChatEvent JSON from the resource file --- .../chatbot/IncomingEventsControllerTest.java | 61 ++++--------------- .../src/test/resources/chat_event.json | 46 ++++++++++++++ 2 files changed, 59 insertions(+), 48 deletions(-) create mode 100644 google-chat-bot/src/test/resources/chat_event.json diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index e7491f48..0c4a13bc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -20,6 +20,7 @@ package io.spine.chatbot; +import com.google.common.io.Resources; import com.google.protobuf.ByteString; import com.google.pubsub.v1.PubsubMessage; import io.micronaut.http.MediaType; @@ -37,9 +38,12 @@ import org.junit.jupiter.api.Test; import javax.inject.Inject; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import static io.micronaut.http.HttpRequest.POST; import static io.spine.chatbot.Application.startServer; +import static io.spine.util.Exceptions.newIllegalStateException; import static org.junit.jupiter.api.Assertions.assertEquals; @MicronautTest @@ -70,7 +74,7 @@ void receiveAndDecode() { var pubsubMessage = PubsubMessage .newBuilder() .setMessageId("129y418y4houfhiuehwr") - .setData(ByteString.copyFromUtf8(CHAT_MESSAGE_EVENT)) + .setData(ByteString.copyFromUtf8(chatEventJson())) .build(); var pushNotification = PubsubPushRequest .newBuilder() @@ -84,51 +88,12 @@ void receiveAndDecode() { assertEquals("OK", actual); } - private static final String CHAT_MESSAGE_EVENT = "" + - "{\n" + - " \"type\":\"MESSAGE\",\n" + - " \"eventTime\":\"2017-03-02T19:02:59.910959Z\",\n" + - " \"space\":{\n" + - " \"name\":\"spaces/AAAAAAAAAAA\",\n" + - " \"displayName\":\"Chuck Norris Discussion Room\",\n" + - " \"type\":\"ROOM\"\n" + - " },\n" + - " \"message\":{\n" + - " \"name\":\"spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC\",\n" + - " \"sender\":{\n" + - " \"name\":\"users/12345678901234567890\",\n" + - " \"displayName\":\"Chuck Norris\",\n" + - " \"avatarUrl\":\"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + - " \"email\":\"chuck@example.com\"\n" + - " },\n" + - " \"createTime\":\"2017-03-02T19:02:59.910959Z\",\n" + - " \"text\":\"@TestBot Violence is my last option.\",\n" + - " \"argumentText\":\" Violence is my last option.\",\n" + - " \"thread\":{\n" + - " \"name\":\"spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB\"\n" + - " },\n" + - " \"annotations\":[\n" + - " {\n" + - " \"length\":8,\n" + - " \"startIndex\":0,\n" + - " \"userMention\":{\n" + - " \"type\":\"MENTION\",\n" + - " \"user\":{\n" + - " \"avatarUrl\":\"https://.../avatar.png\",\n" + - " \"displayName\":\"TestBot\",\n" + - " \"name\":\"users/1234567890987654321\",\n" + - " \"type\":\"BOT\"\n" + - " }\n" + - " },\n" + - " \"type\":\"USER_MENTION\"\n" + - " }\n" + - " ]\n" + - " },\n" + - " \"user\":{\n" + - " \"name\":\"users/12345678901234567890\",\n" + - " \"displayName\":\"Chuck Norris\",\n" + - " \"avatarUrl\":\"https://lh3.googleusercontent.com/.../photo.jpg\",\n" + - " \"email\":\"chuck@example.com\"\n" + - " }\n" + - "}"; + private static String chatEventJson() { + try { + var resource = Resources.getResource("chat_event.json"); + return Resources.toString(resource, StandardCharsets.UTF_8); + } catch (IOException e) { + throw newIllegalStateException(e, "Unable to load ChatEvent message JSON definition."); + } + } } diff --git a/google-chat-bot/src/test/resources/chat_event.json b/google-chat-bot/src/test/resources/chat_event.json new file mode 100644 index 00000000..4f0cb697 --- /dev/null +++ b/google-chat-bot/src/test/resources/chat_event.json @@ -0,0 +1,46 @@ +{ + "type": "MESSAGE", + "eventTime": "2017-03-02T19:02:59.910959Z", + "space": { + "name": "spaces/AAAAAAAAAAA", + "displayName": "Chuck Norris Discussion Room", + "type": "ROOM" + }, + "message": { + "name": "spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC", + "sender": { + "name": "users/12345678901234567890", + "displayName": "Chuck Norris", + "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg", + "email": "chuck@example.com" + }, + "createTime": "2017-03-02T19:02:59.910959Z", + "text": "@TestBot Violence is my last option.", + "argumentText": " Violence is my last option.", + "thread": { + "name": "spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB" + }, + "annotations": [ + { + "length": 8, + "startIndex": 0, + "userMention": { + "type": "MENTION", + "user": { + "avatarUrl": "https://.../avatar.png", + "displayName": "TestBot", + "name": "users/1234567890987654321", + "type": "BOT" + } + }, + "type": "USER_MENTION" + } + ] + }, + "user": { + "name": "users/12345678901234567890", + "displayName": "Chuck Norris", + "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg", + "email": "chuck@example.com" + } +} From e2e0cc9c6729e87363a1afba24a19aedd59c7f44 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:07:37 +0300 Subject: [PATCH 373/492] Fix misprint --- .../io/spine/chatbot/server/github/RepoBuildProcessTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 37a5c68b..9b4e7765 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -53,7 +53,7 @@ final class RepoBuildProcessTest extends GitHubContextAwareTest { private static final SpaceId chatSpace = space("spaces/1245wrq"); @Test - @DisplayName("throw NoBuildsFound rejection when Travic API cannot return builds for a repo") + @DisplayName("throw NoBuildsFound rejection when Travis API cannot return builds for a repo") void throwNoBuildsFoundRejection() { travisClient().setBuildsFor(repository.getValue(), RepoBranchBuildResponse.getDefaultInstance()); From 93b9e9b11ecd268df8e82d4e10cf27840a55f094 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:08:20 +0300 Subject: [PATCH 374/492] Fix event name --- .../io/spine/chatbot/server/github/RepoBuildProcessTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 9b4e7765..e3915b39 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -231,7 +231,7 @@ void sendCheckCommands() { } @Test - @DisplayName("producing BuildStable event") + @DisplayName("producing BuildSucceededAgain event") void producingEvent() { var stateChange = BuildStateChange .newBuilder() From e50941f45a15476569e07019a7353eece72019b4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:13:05 +0300 Subject: [PATCH 375/492] Use static imports for enums --- .../chatbot/server/google/chat/IncomingEventsHandlerTest.java | 4 ++-- .../spine/chatbot/server/google/chat/SpaceAggregateTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index eccac782..777220b1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -25,7 +25,6 @@ import io.spine.chatbot.google.chat.incoming.ChatEvent; import io.spine.chatbot.google.chat.incoming.EventType; import io.spine.chatbot.google.chat.incoming.Message; -import io.spine.chatbot.google.chat.incoming.SpaceType; import io.spine.chatbot.google.chat.incoming.User; import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; import io.spine.chatbot.google.chat.incoming.event.BotRemovedFromSpace; @@ -37,6 +36,7 @@ import static io.spine.chatbot.google.chat.incoming.EventType.ADDED_TO_SPACE; import static io.spine.chatbot.google.chat.incoming.EventType.MESSAGE; import static io.spine.chatbot.google.chat.incoming.EventType.REMOVED_FROM_SPACE; +import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; @@ -132,7 +132,7 @@ private static io.spine.chatbot.google.chat.incoming.Space chatSpace() { return io.spine.chatbot.google.chat.incoming.Space .newBuilder() .setName(spaceId.getValue()) - .setType(SpaceType.ROOM) + .setType(ROOM) .vBuild(); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index f77420c4..fab82b91 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -41,7 +41,7 @@ final class SpaceAggregateTest extends GoogleChatContextAwareTest { private static final SpaceId SPACE = space("spaces/poqwdpQ21"); - private final SpaceHeader HEADER = SpaceHeader + private static final SpaceHeader HEADER = SpaceHeader .newBuilder() .setThreaded(true) .setDisplayName("Spine Developers") From 85ef4d86c6d7f7da1e7cbd84fbf6803b5a2e1112 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:13:20 +0300 Subject: [PATCH 376/492] Use same consistent `ChatBot` name across the project --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a860846..e1f0c05a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,5 +18,5 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -rootProject.name = "chat-bot" +rootProject.name = "ChatBot" include("google-chat-bot") From 9623b404f824d33db7ace31a791a799219f6dc8e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:33:58 +0300 Subject: [PATCH 377/492] Fix misprint --- .../java/io/spine/chatbot/api/google/chat/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java index 5868f089..7c91e66e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java @@ -21,7 +21,7 @@ /** * This package contains Google Chat API facade. * - *

    The usage of the Chat API itself it not straight-forward. That's why it is recommended to + *

    The usage of the Chat API itself it not straightforward. That's why it is recommended to * use the {@link io.spine.chatbot.api.google.chat.GoogleChatClient facade} instead. */ @CheckReturnValue From 67a22722e2451bcb9d54256036e5a30ce6447c6e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:43:18 +0300 Subject: [PATCH 378/492] Define a BuildStateUpdate message that wraps the update sent to the Google Chat --- .../chatbot/api/google/chat/GoogleChat.java | 25 +++++++--- .../api/google/chat/GoogleChatClient.java | 6 +-- .../server/google/chat/ThreadChatProcess.java | 16 ++---- .../spine/chatbot/google/chat/chat.proto | 50 +++++++++++++++++++ .../google/chat/InMemoryGoogleChatClient.java | 19 +++---- .../google/chat/ThreadChatProcessTest.java | 22 ++++---- 6 files changed, 98 insertions(+), 40 deletions(-) create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat.proto diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 420cf395..4442f44f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -30,6 +30,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.api.google.secret.Secrets; import io.spine.chatbot.github.repository.build.Build; +import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.logging.Logging; @@ -41,6 +42,9 @@ import java.security.GeneralSecurityException; import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; +import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; import static io.spine.util.Exceptions.newIllegalStateException; /** @@ -69,19 +73,26 @@ public static GoogleChatClient newInstance() { } @Override - public Message sendBuildStateUpdate(Build buildState, ThreadResource thread) { - var repoSlug = buildState.getRepositorySlug(); + public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { + var repoSlug = build.getRepositorySlug(); var debug = _debug(); debug.log("Building state update message for repository `%s`.", repoSlug); - var message = buildStateMessage(buildState, thread); + var message = buildStateMessage(build, thread); debug.log("Sending state update message for repository `%s`.", repoSlug); - var result = sendMessage(buildState.getSpace(), message); + var sentMessage = sendMessage(build.getSpace(), message); debug.log( "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", - result.getName(), repoSlug, result.getThread() - .getName() + sentMessage.getName(), repoSlug, sentMessage.getThread() + .getName() ); - return result; + return BuildStateUpdate + .newBuilder() + .setMessage(message(message.getName())) + .setResource(threadResource(message.getThread() + .getName())) + .setSpace(build.getSpace()) + .setThread(thread(build.getRepositorySlug())) + .vBuild(); } @CanIgnoreReturnValue diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java index 7196ea82..e2b628d4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java @@ -20,8 +20,8 @@ package io.spine.chatbot.api.google.chat; -import com.google.api.services.chat.v1.model.Message; import io.spine.chatbot.github.repository.build.Build; +import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.thread.ThreadResource; /** @@ -37,7 +37,7 @@ public interface GoogleChatClient { * *

    If the {@code thread} has no name specified the message is sent to a new thread. * - * @return a sent message + * @return a sent build state update */ - Message sendBuildStateUpdate(Build buildState, ThreadResource thread); + BuildStateUpdate sendBuildStateUpdate(Build buildState, ThreadResource thread); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 22c478ba..ab68a375 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -40,10 +40,6 @@ import java.util.Optional; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; -import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; - /** * A process of notifying thread members about the changes in the watched resouces. */ @@ -82,19 +78,17 @@ Pair> on(@External BuildRecovered e) { private Pair> processBuildStateUpdate(Build build, RepositoryId repository) { - var sentMessage = client.sendBuildStateUpdate(build, state().getResource()); - var message = message(sentMessage.getName()); - var thread = thread(repository.getValue()); - var space = build.getSpace(); + var sentUpdate = client.sendBuildStateUpdate(build, state().getResource()); + var space = sentUpdate.getSpace(); + var thread = sentUpdate.getThread(); var messageCreated = MessageCreated .newBuilder() - .setMessage(message) + .setMessage(sentUpdate.getMessage()) .setSpace(space) .setThread(thread) .vBuild(); if (shouldCreateThread()) { - var resource = threadResource(sentMessage.getThread() - .getName()); + var resource = sentUpdate.getResource(); _debug().log("New thread `%s` created for repository `%s`.", resource.getName(), repository.getValue()); builder().setResource(resource) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat.proto new file mode 100644 index 00000000..be42b776 --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/chat.proto @@ -0,0 +1,50 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.chatbot.google.chat; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.google.chat"; +option java_outer_classname = "ChatProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; + +import "spine/chatbot/google/chat/identifiers.proto"; +import "spine/chatbot/google/chat/thread.proto"; + +// A build state update message that was sent to the Chat. +message BuildStateUpdate { + + // The message that was sent to the chat. + MessageId message = 1 [(required) = true]; + + // The space to which the message was sent. + SpaceId space = 2 [(required) = true]; + + // The thread to which the message was sent. + ThreadId thread = 3 [(required) = true]; + + // The resource name of the thread. + ThreadResource resource = 4 [(required) = true]; +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java index 53cbc156..0c6e2599 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java @@ -20,9 +20,9 @@ package io.spine.chatbot.api.google.chat; -import com.google.api.services.chat.v1.model.Message; import io.spine.chatbot.api.FailFastAwareClient; import io.spine.chatbot.github.repository.build.Build; +import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.thread.ThreadResource; import java.util.Map; @@ -35,7 +35,7 @@ */ public final class InMemoryGoogleChatClient extends FailFastAwareClient implements GoogleChatClient { - private final Map sentMessages = new ConcurrentHashMap<>(); + private final Map sentMessages = new ConcurrentHashMap<>(); private InMemoryGoogleChatClient(boolean failFast) { super(failFast); @@ -56,20 +56,21 @@ public static InMemoryGoogleChatClient lenientClient() { } @Override - public Message sendBuildStateUpdate(Build buildState, ThreadResource thread) { + public BuildStateUpdate sendBuildStateUpdate(Build buildState, ThreadResource thread) { var stubbedValue = sentMessages.get(buildState.getNumber()); - var result = failOrDefault(stubbedValue, buildState.getNumber(), new Message()); + var result = failOrDefault(stubbedValue, + buildState.getNumber(), + BuildStateUpdate.getDefaultInstance()); return result; } /** - * Sets up a stub {@code message} for a build state update with the specified - * {@code buildNumber}. + * Sets up a stub {@code update} for a build state with the specified {@code buildNumber}. */ - public void setMessageForBuildStatusUpdate(String buildNumber, Message message) { + public void setBuildStateUpdate(String buildNumber, BuildStateUpdate update) { checkNotNull(buildNumber); - checkNotNull(message); - sentMessages.put(buildNumber, message); + checkNotNull(update); + sentMessages.put(buildNumber, update); } /** diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index daa4c88c..cce842d3 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -20,14 +20,13 @@ package io.spine.chatbot.server.google.chat; -import com.google.api.services.chat.v1.model.Message; -import com.google.api.services.chat.v1.model.Thread; import io.spine.base.EventMessage; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; +import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.event.MessageCreated; @@ -87,14 +86,17 @@ private abstract static class BuildStateChanged extends GoogleChatContextAwareTe private final ThreadId thread = thread(repository.getValue()); private final SpaceId space = space("spaces/1241pjwqe"); - private final Thread newThread = new Thread().setName("spaces/1241pjwqe/threads/k12d1o2r1"); - private final Message sentMessage = new Message() - .setName("spaces/1241pjwqe/messages/12154363643624") - .setThread(newThread); + private final BuildStateUpdate stateUpdate = BuildStateUpdate + .newBuilder() + .setSpace(space) + .setMessage(message("spaces/1241pjwqe/messages/12154363643624")) + .setThread(thread) + .setResource(threadResource("spaces/1241pjwqe/threads/k12d1o2r1")) + .vBuild(); @BeforeEach void receiveBuildStateChange() { - googleChatClient().setMessageForBuildStatusUpdate(buildNumber, sentMessage); + googleChatClient().setBuildStateUpdate(buildNumber, stateUpdate); var newBuildState = Build .newBuilder() .setSpace(space) @@ -116,14 +118,14 @@ abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, void producingEvents() { var messageCreated = MessageCreated .newBuilder() - .setMessage(message(sentMessage.getName())) + .setMessage(stateUpdate.getMessage()) .setThread(thread) .setSpace(space) .vBuild(); var threadCreated = ThreadCreated .newBuilder() .setThread(thread) - .setResource(threadResource(newThread.getName())) + .setResource(stateUpdate.getResource()) .setSpace(space) .vBuild(); context().assertEvent(messageCreated); @@ -137,7 +139,7 @@ void settingState() { .newBuilder() .setThread(thread) .setSpace(space) - .setResource(threadResource(newThread.getName())) + .setResource(stateUpdate.getResource()) .vBuild(); context().assertState(thread, ThreadChat.class) .isEqualTo(expectedState); From 226c383f4aacaa6de26fe3c1187c1e9f3de0c476 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 14:44:52 +0300 Subject: [PATCH 379/492] shorten param name --- .../io/spine/chatbot/api/google/chat/GoogleChatClient.java | 6 +++--- .../chatbot/api/google/chat/InMemoryGoogleChatClient.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java index e2b628d4..b1e2b466 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java @@ -33,11 +33,11 @@ public interface GoogleChatClient { /** - * Sends {@link Build} status message to a related space and thread. + * Sends {@link Build} state update message to the related space and thread. * *

    If the {@code thread} has no name specified the message is sent to a new thread. * - * @return a sent build state update + * @return a sent build state update message */ - BuildStateUpdate sendBuildStateUpdate(Build buildState, ThreadResource thread); + BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java index 0c6e2599..d031f9a1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java @@ -56,10 +56,10 @@ public static InMemoryGoogleChatClient lenientClient() { } @Override - public BuildStateUpdate sendBuildStateUpdate(Build buildState, ThreadResource thread) { - var stubbedValue = sentMessages.get(buildState.getNumber()); + public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { + var stubbedValue = sentMessages.get(build.getNumber()); var result = failOrDefault(stubbedValue, - buildState.getNumber(), + build.getNumber(), BuildStateUpdate.getDefaultInstance()); return result; } From 592107d11da064e420d8ec6bbe0536d1c8d11ece Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:05:10 +0300 Subject: [PATCH 380/492] Cleanup docs. Improve wording --- .../main/java/io/spine/chatbot/api/travis/BuildsQuery.java | 6 +++--- .../main/java/io/spine/chatbot/api/travis/ReposQuery.java | 2 +- .../src/main/java/io/spine/chatbot/api/travis/Travis.java | 4 ++-- .../main/java/io/spine/chatbot/delivery/ShardDelivery.java | 2 +- .../io/spine/chatbot/server/github/BuildStateMixin.java | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index a790bbb1..b2e8be51 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -21,7 +21,7 @@ package io.spine.chatbot.api.travis; /** - * Travis CI API query for finding repo branch builds. + * A branch builds query to the Travis CI API. * * @see Find branch build */ @@ -36,8 +36,8 @@ private BuildsQuery(String request) { * *

    Requests the latest build from the {@code master} branch. */ - public static BuildsQuery forRepo(String repoSlug) { - var encodedSlug = encode(repoSlug); + public static BuildsQuery forRepo(String slug) { + var encodedSlug = encode(slug); var request = "/repo/" + encodedSlug + "/branch/master?&include=build.commit,build.created_by"; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java index 44f2a52e..957b8b24 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java @@ -21,7 +21,7 @@ package io.spine.chatbot.api.travis; /** - * Travis CI repositories API query. + * A repositories query to the Travis CI API. * * @see * Repos for owner diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index 9fd9278e..2e24994c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -31,7 +31,7 @@ import static java.lang.String.format; /** - * A Travis CI REST API client. + * A client to the Travis CI REST API. * * @see Travis CI API */ @@ -53,7 +53,7 @@ private Travis(String token) { } /** - * Creates a new Travis client with the default secure Travis token. + * Creates a new Travis client with the default Travis token. */ public static TravisClient newInstance() { return new Travis(Secrets.travisToken()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java index 313a71f6..95a8958b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -27,7 +27,7 @@ import io.spine.server.delivery.ShardedRecord; /** - * Performs the delivery of the messages from a particular shard. + * Delivers messages from a particular shard. * *

    Wraps the {@link io.spine.server.delivery.Delivery#deliverMessagesFrom(ShardIndex) * Delivery#deliverMessagesFrom} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java index 731e1bc0..5b35a0be 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -58,8 +58,9 @@ default boolean failed() { default String stateLabel() { var state = getState(); var name = state.name(); - return name.charAt(0) + name.substring(1) - .toLowerCase(); + var result = name.charAt(0) + name.substring(1) + .toLowerCase(); + return result; } /** From 4eefbb9777b557a7afa1cc918aeb41916d0f903a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:15:28 +0300 Subject: [PATCH 381/492] Improve wording --- .../spine/chatbot/github/organization_init_commands.proto | 5 ++++- .../spine/chatbot/github/organization_repositories.proto | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index 9e65068f..638f6506 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -33,7 +33,10 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; import "spine/chatbot/google/chat/identifiers.proto"; -// Initialize watched organization resources command. +// A request to initialize watched organization resources. +// +// Registers the organization itself and the related repositories to be watched by the ChatBot. +// message InitializeOrganization { // The organization to perform initialization for. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 90583c86..501d53be 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -32,7 +32,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/github/identifiers.proto"; -// Organization repositories. +// Lists repositories of an organization. message OrganizationRepositories { option (entity) = {kind: PROJECTION visibility: FULL}; From da1f5b991395f04c9a9c22ad72afd57560f1ea39 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:15:55 +0300 Subject: [PATCH 382/492] move `Commit` out of the `Build` --- .../server/github/RepoBuildProcess.java | 6 +-- .../chatbot/github/repository_build.proto | 41 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 282a089b..75e5c6f1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -24,12 +24,12 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; import io.spine.chatbot.api.travis.BuildsQuery; -import io.spine.chatbot.api.travis.Commit; import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; +import io.spine.chatbot.github.repository.build.Commit; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; import io.spine.chatbot.github.repository.build.event.BuildFailed; @@ -180,8 +180,8 @@ static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { .vBuild(); } - private static Build.Commit from(Commit commit) { - return Build.Commit + private static Commit from(io.spine.chatbot.api.travis.Commit commit) { + return Commit .newBuilder() .setSha(commit.getSha()) .setMessage(commit.getMessage()) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 2fb56e7a..6d197001 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -46,16 +46,15 @@ message RepositoryBuild { // The time of the last status check. .google.protobuf.Timestamp last_status_check = 2; - // The current state. + // The current build. Build build = 3; - // Current repository build state. + // The current repository state. Build.State current_state = 4 [(column) = true]; } -// State of the build for a repository branch. +// A repository branch build. message Build { - option (is).java_type = "io.spine.chatbot.server.github.BuildStateMixin"; // Incremental number for a repository's builds. @@ -111,30 +110,30 @@ message Build { // The User or Organization that created the build. string created_by = 7; - // A git commit. - message Commit { + // The repository slug the build is associated with. + string repository_slug = 8; - // Checksum the commit has in git and is identified by. - string sha = 1; + // The Google Chat space associated with the organization. + spine.chatbot.google.chat.SpaceId space = 9 [(required) = true, (validate) = true]; +} - // Commit message. - string message = 2; +// A git commit. +message Commit { - // URL to the commit's diff on GitHub. - spine.net.Url compare_url = 3; + // Checksum the commit has in git and is identified by. + string sha = 1; - // Commit date from git. - string committed_at = 4; + // Commit message. + string message = 2; - // Commit author from git. - string authored_by = 5; - } + // URL to the commit's diff on GitHub. + spine.net.Url compare_url = 3; - // The repository slug the build is associated with. - string repository_slug = 8; + // Commit date from git. + string committed_at = 4; - // The Google Chat space associated with the organization. - spine.chatbot.google.chat.SpaceId space = 9 [(required) = true, (validate) = true]; + // Commit author from git. + string authored_by = 5; } // Definition of a change in a `build_state` field. From db49ddaf53050fb0e19d467f5b22ee3d48af98de Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:25:18 +0300 Subject: [PATCH 383/492] Improve wording --- .../io/spine/chatbot/server/google/chat/ThreadAggregate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index 455341b8..5c3cb8b2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -35,7 +35,7 @@ * A thread in the chat room. * *

    A new thread is initialized as early as a new conversation is started in the room. - * It is being initialized with the creation of the first message of the conversation. + * It happens once the first message is posted to the conversation. */ final class ThreadAggregate extends Aggregate implements Logging { From d632e8ce5763cbb288e2a69f1ba7177c21d4a21b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:25:28 +0300 Subject: [PATCH 384/492] Separate logs and refine log levels --- .../chatbot/server/google/chat/IncomingEventsHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 2f00c04c..03fc0e0a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -77,10 +77,12 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin return EitherOf4.withB(botRemovedFromSpace(chatEvent)); case CARD_CLICKED: + _debug().log("Skipping card clicks."); + return EitherOf4.withD(nothing()); case UNRECOGNIZED: case ET_UNKNOWN: default: - _debug().log("Unsupported chat event type received: %s", chatEvent.getType()); + _error().log("Unsupported chat event type received: %s", chatEvent.getType()); return EitherOf4.withD(nothing()); } } From abeadc5e0942bb30c3c6186c13bf1da8733c597e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:38:29 +0300 Subject: [PATCH 385/492] Extract ChatEvents utility --- .../server/google/chat/ChatEvents.java | 81 +++++++++++++++++++ .../google/chat/IncomingEventsHandler.java | 36 +-------- .../server/google/chat/ChatEventsTest.java | 32 ++++++++ 3 files changed, 116 insertions(+), 33 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ChatEventsTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java new file mode 100644 index 00000000..55a2c969 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java @@ -0,0 +1,81 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.chatbot.google.chat.incoming.ChatEvent; +import io.spine.chatbot.google.chat.incoming.event.BotAddedToSpace; +import io.spine.chatbot.google.chat.incoming.event.BotRemovedFromSpace; +import io.spine.chatbot.google.chat.incoming.event.MessageReceived; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; + +/** + * A utility for working with {@link ChatEvent}s. + */ +final class ChatEvents { + + /** + * Prevents instantiation of this utility class. + */ + private ChatEvents() { + } + + /** + * Creates a new {@code BotRemovedFromSpace} message out of the supplied {@code event}. + */ + static BotRemovedFromSpace toBotRemovedFromSpace(ChatEvent event) { + checkNotNull(event); + var space = event.getSpace(); + return BotRemovedFromSpace + .newBuilder() + .setEvent(event) + .setSpace(space(space.getName())) + .vBuild(); + } + + /** + * Creates a new {@code BotAddedToSpace} message out of the supplied {@code event}. + */ + static BotAddedToSpace toBotAddedToSpace(ChatEvent event) { + checkNotNull(event); + var space = event.getSpace(); + return BotAddedToSpace + .newBuilder() + .setEvent(event) + .setSpace(space(space.getName())) + .vBuild(); + } + + /** + * Creates a new {@code MessageReceived} message out of the supplied {@code event}. + */ + static MessageReceived toMessageReceived(ChatEvent event) { + checkNotNull(event); + var message = event.getMessage(); + return MessageReceived + .newBuilder() + .setEvent(event) + .setMessage(message(message.getName())) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 03fc0e0a..ddfc9a69 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -32,9 +32,6 @@ import io.spine.server.model.Nothing; import io.spine.server.tuple.EitherOf4; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; - /** * Google Chat incoming events reactor. * @@ -64,17 +61,17 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin switch (chatEvent.getType()) { case MESSAGE: _info().log("New user message received."); - return EitherOf4.withC(messageReceived(chatEvent)); + return EitherOf4.withC(ChatEvents.toMessageReceived(chatEvent)); case ADDED_TO_SPACE: var toSpace = chatEvent.getSpace(); _info().log("ChatBot added to space `%s` (%s).", toSpace.getDisplayName(), toSpace.getName()); - return EitherOf4.withA(botAddedToSpace(chatEvent)); + return EitherOf4.withA(ChatEvents.toBotAddedToSpace(chatEvent)); case REMOVED_FROM_SPACE: var fromSpace = chatEvent.getSpace(); _info().log("ChatBot removed from space `%s` (%s).", fromSpace.getDisplayName(), fromSpace.getName()); - return EitherOf4.withB(botRemovedFromSpace(chatEvent)); + return EitherOf4.withB(ChatEvents.toBotRemovedFromSpace(chatEvent)); case CARD_CLICKED: _debug().log("Skipping card clicks."); @@ -86,31 +83,4 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin return EitherOf4.withD(nothing()); } } - - private static BotRemovedFromSpace botRemovedFromSpace(ChatEvent chatEvent) { - var space = chatEvent.getSpace(); - return BotRemovedFromSpace - .newBuilder() - .setEvent(chatEvent) - .setSpace(space(space.getName())) - .vBuild(); - } - - private static BotAddedToSpace botAddedToSpace(ChatEvent chatEvent) { - var space = chatEvent.getSpace(); - return BotAddedToSpace - .newBuilder() - .setEvent(chatEvent) - .setSpace(space(space.getName())) - .vBuild(); - } - - private static MessageReceived messageReceived(ChatEvent chatEvent) { - var message = chatEvent.getMessage(); - return MessageReceived - .newBuilder() - .setEvent(chatEvent) - .setMessage(message(message.getName())) - .vBuild(); - } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ChatEventsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ChatEventsTest.java new file mode 100644 index 00000000..849111a4 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ChatEventsTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.google.chat; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("`ChatEvents` should") +final class ChatEventsTest extends UtilityClassTest { + + ChatEventsTest() { + super(ChatEvents.class); + } +} From 0ce51581e5cb441eba2ae877e6bda2639c2885c9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:40:31 +0300 Subject: [PATCH 386/492] Drop repetitive part of the `@BoundedContext` docs --- .../main/java/io/spine/chatbot/server/github/package-info.java | 3 --- .../java/io/spine/chatbot/server/google/chat/package-info.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java index b2a85844..91fd9c98 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/package-info.java @@ -20,9 +20,6 @@ /** * This package contains server-side implementation of the GitHub Context. - * - *

    This package is annotated with {@code BoundedContext} annotation to mark - * entities of this package (and sub-packages, if any) as parts of the context. */ @BoundedContext(GitHubContext.GIT_HUB_CONTEXT_NAME) @CheckReturnValue diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java index 8f4e5c3a..ea2b8728 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/package-info.java @@ -20,9 +20,6 @@ /** * This package contains server-side implementation of the Google Chat Context. - * - *

    This package is annotated with {@code BoundedContext} annotation to mark - * entities of this package (and sub-packages, if any) as parts of the context. */ @BoundedContext(GoogleChatContext.GOOGLE_CHAT_CONTEXT_NAME) @CheckReturnValue From a4c42ce299ea63f2479aa03e01be332e6da1a360 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 30 Jun 2020 15:43:00 +0300 Subject: [PATCH 387/492] Rename param --- .../java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java index 88ff3847..7ebffdaa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java @@ -54,7 +54,7 @@ static JsonProtoBodyHandler jsonBodyHandler(Class type } @Override - public HttpResponse.BodySubscriber apply(ResponseInfo responseInfo) { + public HttpResponse.BodySubscriber apply(ResponseInfo response) { return BodySubscribers.mapping(BodySubscribers.ofString(StandardCharsets.UTF_8), this::parseJson); } From d4b75199990db053e06c33159130a3061d0f8c7f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 12:57:27 +0300 Subject: [PATCH 388/492] Introduce reusable `Slug` type --- .../api/google/chat/BuildStateUpdates.java | 3 +- .../chatbot/api/google/chat/GoogleChat.java | 4 +- .../spine/chatbot/api/travis/BuildsQuery.java | 8 ++- .../io/spine/chatbot/api/travis/Query.java | 11 ---- .../spine/chatbot/api/travis/ReposQuery.java | 6 +- .../server/github/RepoBuildProcess.java | 4 +- .../chatbot/server/github/SlugMixin.java | 57 ++++++++++++++++ .../io/spine/chatbot/server/github/Slugs.java | 66 +++++++++++++++++++ .../server/github/SpineOrgInitProcess.java | 2 +- .../chatbot/github/repository_build.proto | 3 +- .../proto/spine/chatbot/github/slug.proto | 22 +++++++ .../api/travis/InMemoryTravisClient.java | 11 ++-- .../server/github/RepoBuildProcessTest.java | 15 +++-- .../chatbot/server/github/SlugMixinTest.java | 36 ++++++++++ .../chatbot/server/github/SlugsTest.java | 32 +++++++++ .../github/SpineOrgInitProcessTest.java | 2 +- 16 files changed, 246 insertions(+), 36 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java create mode 100644 google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index c66c3cbb..db5aa574 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -65,7 +65,8 @@ static Message buildStateMessage(Build build, ThreadResource thread) { checkNotNull(thread); var headerIcon = build.failed() ? FAILURE_ICON : SUCCESS_ICON; var cardHeader = new CardHeader() - .setTitle(build.getRepositorySlug()) + .setTitle(build.getRepository() + .getValue()) .setImageUrl(headerIcon); var sections = ImmutableList.of( buildStateSection(build), diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 4442f44f..4577b4fb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -74,7 +74,7 @@ public static GoogleChatClient newInstance() { @Override public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { - var repoSlug = build.getRepositorySlug(); + var repoSlug = build.getRepository(); var debug = _debug(); debug.log("Building state update message for repository `%s`.", repoSlug); var message = buildStateMessage(build, thread); @@ -91,7 +91,7 @@ public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) .setResource(threadResource(message.getThread() .getName())) .setSpace(build.getSpace()) - .setThread(thread(build.getRepositorySlug())) + .setThread(thread(repoSlug.getValue())) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java index b2e8be51..af68e3eb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java @@ -20,6 +20,8 @@ package io.spine.chatbot.api.travis; +import io.spine.chatbot.github.Slug; + /** * A branch builds query to the Travis CI API. * @@ -32,12 +34,12 @@ private BuildsQuery(String request) { } /** - * Creates a query for a repository with the specified {@code slug}. + * Creates a query for the {@code repository}. * *

    Requests the latest build from the {@code master} branch. */ - public static BuildsQuery forRepo(String slug) { - var encodedSlug = encode(slug); + public static BuildsQuery forRepo(Slug repository) { + var encodedSlug = repository.encodedValue(); var request = "/repo/" + encodedSlug + "/branch/master?&include=build.commit,build.created_by"; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java index 7a2f0e0e..a57cbbf6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java @@ -23,9 +23,6 @@ import com.google.common.base.MoreObjects; import com.google.common.base.Objects; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - import static com.google.common.base.Preconditions.checkNotNull; /** @@ -61,14 +58,6 @@ Class responseType() { return responseType; } - /** - * Encodes passed value using {@link URLEncoder} and - * {@link StandardCharsets#UTF_8 UTF_8} charset. - */ - static String encode(String value) { - return URLEncoder.encode(value, StandardCharsets.UTF_8); - } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java index 957b8b24..712e8bd3 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java @@ -20,6 +20,8 @@ package io.spine.chatbot.api.travis; +import io.spine.chatbot.github.Slug; + /** * A repositories query to the Travis CI API. * @@ -36,8 +38,8 @@ private ReposQuery(String request) { * Creates a repository query for repositories of the specified {@code owner} * (either a user or an organization). */ - public static ReposQuery forOwner(String owner) { - var encodedOwner = encode(owner); + public static ReposQuery forOwner(Slug owner) { + var encodedOwner = owner.encodedValue(); var request = "/owner/" + encodedOwner + "/repos"; return new ReposQuery(request); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 75e5c6f1..6d9ea2aa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -82,7 +82,7 @@ EitherOf3 handle(CheckReposito throws NoBuildsFound { var repository = c.getRepository(); _info().log("Checking build status for the repository `%s`.", repository.getValue()); - var branchBuild = client.execute(BuildsQuery.forRepo(repository.getValue())); + var branchBuild = client.execute(BuildsQuery.forRepo(Slugs.forRepo(repository))); if (isDefault(branchBuild.getLastBuild())) { _warn().log("No builds found for the repository `%s`.", repository.getValue()); throw NoBuildsFound @@ -175,7 +175,7 @@ static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { .setLastCommit(from(build.getCommit())) .setCreatedBy(build.getCreatedBy() .getLogin()) - .setRepositorySlug(slug) + .setRepository(Slugs.create(slug)) .setTravisCiUrl(travisBuildUrlFor(slug, build.getId())) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java new file mode 100644 index 00000000..56aa35d6 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java @@ -0,0 +1,57 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.github.SlugOrBuilder; +import io.spine.chatbot.github.repository.build.Build; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * Augments {@link Build} with useful methods. + */ +@GeneratedMixin +public interface SlugMixin extends SlugOrBuilder { + + /** + * Returns the slug {@code value}. + */ + default String value() { + return getValue(); + } + + /** + * Returns URL-encoded slug {@code value}. + */ + default String encodedValue() { + return encode(getValue()); + } + + /** + * Encodes passed value using {@link URLEncoder} and + * {@link StandardCharsets#UTF_8 UTF_8} charset. + */ + private static String encode(String value) { + return URLEncoder.encode(value, StandardCharsets.UTF_8); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java new file mode 100644 index 00000000..2670e105 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java @@ -0,0 +1,66 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.Slug; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; + +/** + * A utility for working with {@link Slug}s. + */ +public final class Slugs { + + /** + * Prevents instantiation of this utility class. + */ + private Slugs() { + } + + /** + * Creates a new {@code Slug} for the {@code repository}. + */ + public static Slug forRepo(RepositoryId repo) { + checkNotNull(repo); + return create(repo.getValue()); + } + + /** + * Creates a new {@code Slug} for the {@code organization}. + */ + public static Slug forOrg(OrganizationId org) { + checkNotNull(org); + return create(org.getValue()); + } + + /** + * Creates a new {@code Slug} with the specified {@code value}. + */ + public static Slug create(String value) { + checkNotEmptyOrBlank(value); + return Slug.newBuilder() + .setValue(value) + .vBuild(); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index af94eb16..5214fe57 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -84,7 +84,7 @@ Iterable on(@External SpaceRegistered e) { _info().log("Starting Spine organization initialization process in space `%s`.", space); var commands = ImmutableSet.builder(); commands.add(registerOrgCommand(ORGANIZATION, space)); - client.execute(ReposQuery.forOwner(ORGANIZATION.getValue())) + client.execute(ReposQuery.forOwner(Slugs.forOrg(ORGANIZATION))) .getRepositoriesList() .stream() .filter(repository -> WATCHED_REPOS.contains(repository.getName())) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 6d197001..001f9e83 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -35,6 +35,7 @@ import "google/protobuf/timestamp.proto"; import "spine/net/url.proto"; import "spine/chatbot/github/identifiers.proto"; +import "spine/chatbot/github/slug.proto"; import "spine/chatbot/google/chat/identifiers.proto"; // A build process of a GitHub repository. @@ -111,7 +112,7 @@ message Build { string created_by = 7; // The repository slug the build is associated with. - string repository_slug = 8; + Slug repository = 8; // The Google Chat space associated with the organization. spine.chatbot.google.chat.SpaceId space = 9 [(required) = true, (validate) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto new file mode 100644 index 00000000..aab26d1b --- /dev/null +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package spine.chatbot.github; + +import "spine/options.proto"; + +option (type_url_prefix) = "type.spine.io.chatbot"; +option java_package = "io.spine.chatbot.github"; +option java_outer_classname = "SlugProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; + +// A unique human-readable identifier. +message Slug { + option (is).java_type = "io.spine.chatbot.server.github.SlugMixin"; + + // The slug value. + // + // E.g. it could be a GitHub repository slug in the format `SpineEventEngine/base`. + // + string value = 1 [(required) = true]; +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java index 677ccd16..3310e3bd 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java @@ -21,6 +21,7 @@ package io.spine.chatbot.api.travis; import io.spine.chatbot.api.FailFastAwareClient; +import io.spine.chatbot.github.Slug; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -63,18 +64,18 @@ public T execute(Query query) { } /** - * Sets up a stub {@code branchBuild} response for a specified {@code repoSlug}. + * Sets up a stub {@code branchBuild} response for a specified {@code repository}. */ - public void setBuildsFor(String repoSlug, RepoBranchBuildResponse branchBuild) { - checkNotNull(repoSlug); + public void setBuildsFor(Slug repository, RepoBranchBuildResponse branchBuild) { + checkNotNull(repository); checkNotNull(branchBuild); - responses.put(BuildsQuery.forRepo(repoSlug), branchBuild); + responses.put(BuildsQuery.forRepo(repository), branchBuild); } /** * Sets up a stub {@code repositories} response for a specified {@code owner}. */ - public void setRepositoriesFor(String owner, RepositoriesResponse repositories) { + public void setRepositoriesFor(Slug owner, RepositoriesResponse repositories) { checkNotNull(owner); checkNotNull(repositories); responses.put(ReposQuery.forOwner(owner), repositories); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index e3915b39..3d607248 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -55,7 +55,7 @@ final class RepoBuildProcessTest extends GitHubContextAwareTest { @Test @DisplayName("throw NoBuildsFound rejection when Travis API cannot return builds for a repo") void throwNoBuildsFoundRejection() { - travisClient().setBuildsFor(repository.getValue(), + travisClient().setBuildsFor(Slugs.forRepo(repository), RepoBranchBuildResponse.getDefaultInstance()); var checkRepoBuild = CheckRepositoryBuild .newBuilder() @@ -83,7 +83,7 @@ final class FailedBuild { @BeforeEach void sendCheckCommand() { - travisClient().setBuildsFor(repository.getValue(), branchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repository), branchBuild); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setRepository(repository) @@ -138,7 +138,7 @@ final class RecoveredBuild { @BeforeEach void sendCheckCommands() { - travisClient().setBuildsFor(repository.getValue(), previousBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repository), previousBranchBuild); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setRepository(repository) @@ -146,7 +146,7 @@ void sendCheckCommands() { .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repository.getValue(), newBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repository), newBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setRepository(repository) @@ -204,7 +204,8 @@ final class StableBuild { @BeforeEach void sendCheckCommands() { - travisClient().setBuildsFor(repository.getValue(), branchBuildOf(initialFailedBuild)); + travisClient().setBuildsFor(Slugs.forRepo(repository), + branchBuildOf(initialFailedBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setRepository(repository) @@ -212,7 +213,7 @@ void sendCheckCommands() { .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(repository.getValue(), previousBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repository), previousBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setRepository(repository) @@ -220,7 +221,7 @@ void sendCheckCommands() { .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); - travisClient().setBuildsFor(repository.getValue(), newBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repository), newBranchBuild); var checkRepoStable = CheckRepositoryBuild .newBuilder() .setRepository(repository) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java new file mode 100644 index 00000000..bd0a61e8 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("`SlugMixin` should") +final class SlugMixinTest { + + @Test + @DisplayName("encode slug value") + void encodeSlugValue() { + var slug = Slugs.create("TestOrganization/test-repository"); + Assertions.assertEquals("TestOrganization%2Ftest-repository", slug.encodedValue()); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java new file mode 100644 index 00000000..24d56ce7 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.testing.UtilityClassTest; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("`Slugs` should") +final class SlugsTest extends UtilityClassTest { + + SlugsTest() { + super(Slugs.class); + } +} diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index d69348d1..a7af9d7b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -60,7 +60,7 @@ void registerSpace() { .newBuilder() .addRepositories(repository) .vBuild(); - travisClient().setRepositoriesFor(ORGANIZATION.getValue(), repositoriesResponse); + travisClient().setRepositoriesFor(Slugs.forOrg(ORGANIZATION), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() .setSpace(space) From bf33aabec0469e50e32213f9d3281d1737f438c2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 12:59:15 +0300 Subject: [PATCH 389/492] Add helper `id` method to the space mixin --- .../spine/chatbot/server/google/chat/ChatEvents.java | 5 ++--- .../server/google/chat/incoming/SpaceMixin.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java index 55a2c969..6b253d30 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java @@ -27,7 +27,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; /** * A utility for working with {@link ChatEvent}s. @@ -49,7 +48,7 @@ static BotRemovedFromSpace toBotRemovedFromSpace(ChatEvent event) { return BotRemovedFromSpace .newBuilder() .setEvent(event) - .setSpace(space(space.getName())) + .setSpace(space.id()) .vBuild(); } @@ -62,7 +61,7 @@ static BotAddedToSpace toBotAddedToSpace(ChatEvent event) { return BotAddedToSpace .newBuilder() .setEvent(event) - .setSpace(space(space.getName())) + .setSpace(space.id()) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java index 4257ffa6..4ee964e0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java @@ -21,9 +21,12 @@ package io.spine.chatbot.server.google.chat.incoming; import io.spine.annotation.GeneratedMixin; +import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.incoming.SpaceOrBuilder; import io.spine.chatbot.google.chat.incoming.SpaceType; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; + /** * Provides utility helpers for the {@link io.spine.chatbot.google.chat.incoming.Space Space} type. */ @@ -38,4 +41,11 @@ public interface SpaceMixin extends SpaceOrBuilder { default boolean isThreaded() { return getType() == SpaceType.ROOM; } + + /** + * Returns the space ID. + */ + default SpaceId id() { + return space(getName()); + } } From 973c861019398309938aa956eb60af6eb6d1d368 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 13:00:21 +0300 Subject: [PATCH 390/492] Use proper link --- .../main/java/io/spine/chatbot/server/github/SlugMixin.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java index 56aa35d6..f0ec90fe 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java @@ -22,13 +22,12 @@ import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.github.SlugOrBuilder; -import io.spine.chatbot.github.repository.build.Build; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; /** - * Augments {@link Build} with useful methods. + * Augments {@link io.spine.chatbot.github.Slug Slug} with useful methods. */ @GeneratedMixin public interface SlugMixin extends SlugOrBuilder { From 25c14920ebe4f82bc252bc033293b8dad03973c6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 13:01:29 +0300 Subject: [PATCH 391/492] Use shortcut method --- .../chatbot/api/google/chat/BuildStateUpdates.java | 2 +- .../io/spine/chatbot/api/google/chat/GoogleChat.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java index db5aa574..de4906c1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java @@ -66,7 +66,7 @@ static Message buildStateMessage(Build build, ThreadResource thread) { var headerIcon = build.failed() ? FAILURE_ICON : SUCCESS_ICON; var cardHeader = new CardHeader() .setTitle(build.getRepository() - .getValue()) + .value()) .setImageUrl(headerIcon); var sections = ImmutableList.of( buildStateSection(build), diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 4577b4fb..cc85a7b7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -74,16 +74,16 @@ public static GoogleChatClient newInstance() { @Override public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { - var repoSlug = build.getRepository(); + var repo = build.getRepository(); var debug = _debug(); - debug.log("Building state update message for repository `%s`.", repoSlug); + debug.log("Building state update message for repository `%s`.", repo); var message = buildStateMessage(build, thread); - debug.log("Sending state update message for repository `%s`.", repoSlug); + debug.log("Sending state update message for repository `%s`.", repo); var sentMessage = sendMessage(build.getSpace(), message); debug.log( "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", - sentMessage.getName(), repoSlug, sentMessage.getThread() - .getName() + sentMessage.getName(), repo, sentMessage.getThread() + .getName() ); return BuildStateUpdate .newBuilder() @@ -91,7 +91,7 @@ public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) .setResource(threadResource(message.getThread() .getName())) .setSpace(build.getSpace()) - .setThread(thread(repoSlug.getValue())) + .setThread(thread(repo.value())) .vBuild(); } From 3a8975bc10e58c5975369c5e7a367091686edf65 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 13:12:09 +0300 Subject: [PATCH 392/492] Extract Travis `Token` secret. --- .../chatbot/api/google/secret/Secrets.java | 28 ++++------ .../io/spine/chatbot/api/travis/Token.java | 54 +++++++++++++++++++ .../io/spine/chatbot/api/travis/Travis.java | 18 +++---- 3 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java index b8a260b6..a0d3439c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java @@ -30,25 +30,13 @@ /** * Utility for accessing application secrets stored in Google Secret Manager. */ -public final class Secrets { +public abstract class Secrets { @SuppressWarnings("CallToSystemGetenv") private static final String PROJECT_ID = System.getenv("GCP_PROJECT_ID"); - private static final String TRAVIS_API_TOKEN = "TravisApiToken"; private static final String CHAT_SERVICE_ACCOUNT = "ChatServiceAccount"; - /** - * Prevents direct instantiation of the utility class. - */ - private Secrets() { - } - - /** - * Retrieves the Travis CI API access token. - */ - public static String travisToken() { - var result = retrieveSecret(TRAVIS_API_TOKEN); - return result; + protected Secrets() { } /** @@ -59,16 +47,22 @@ public static String chatServiceAccount() { return result; } - private static String retrieveSecret(String secretName) { + /** + * Retrieves the secret with the specified {@code name}. + * + *

    The latest version of the secret available in the current {@link #PROJECT_ID project} + * is retrieved. + */ + protected static String retrieveSecret(String name) { try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) { - var secretVersion = SecretVersionName.of(PROJECT_ID, secretName, "latest"); + var secretVersion = SecretVersionName.of(PROJECT_ID, name, "latest"); var secret = client.accessSecretVersion(secretVersion) .getPayload() .getData() .toStringUtf8(); return secret; } catch (IOException e) { - throw newIllegalStateException(e, "Unable to retrieve secret `%s`.", secretName); + throw newIllegalStateException(e, "Unable to retrieve secret `%s`.", name); } } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java new file mode 100644 index 00000000..f82ecb84 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java @@ -0,0 +1,54 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api.travis; + +import io.spine.chatbot.api.google.secret.Secrets; + +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; + +/** + * A secret Travis CI API token. + */ +final class Token extends Secrets { + + private static final String TRAVIS_API_TOKEN = "TravisApiToken"; + + private final String value; + + private Token(String value) { + this.value = value; + } + + /** + * Returns the token value. + */ + String value() { + return value; + } + + /** + * Creates the Travis CI API access token. + */ + static Token secretToken() { + var value = checkNotEmptyOrBlank(retrieveSecret(TRAVIS_API_TOKEN)); + return new Token(value); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index 2e24994c..1e4f2f0f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -20,14 +20,14 @@ package io.spine.chatbot.api.travis; -import io.spine.chatbot.api.google.secret.Secrets; - import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; +import static com.google.api.client.util.Preconditions.checkNotNull; import static io.spine.chatbot.api.travis.JsonProtoBodyHandler.jsonBodyHandler; +import static io.spine.chatbot.api.travis.Token.secretToken; import static java.lang.String.format; /** @@ -43,20 +43,20 @@ public final class Travis implements TravisClient { private static final String API_VERSION = "3"; private static final String AUTH_HEADER = "Authorization"; - private final String apiToken; + private final Token apiToken; /** * Creates a new Travis client with the specified API token. */ - private Travis(String token) { - apiToken = token; + private Travis(Token apiToken) { + this.apiToken = checkNotNull(apiToken); } /** * Creates a new Travis client with the default Travis token. */ public static TravisClient newInstance() { - return new Travis(Secrets.travisToken()); + return new Travis(secretToken()); } @Override @@ -78,17 +78,17 @@ private T execute(String request, Class responseTy } } - private static HttpRequest apiRequest(String request, String token) { + private static HttpRequest apiRequest(String request, Token token) { return authorizedApiRequest(token) .uri(URI.create(BASE_URL + request)) .build(); } - private static HttpRequest.Builder authorizedApiRequest(String token) { + private static HttpRequest.Builder authorizedApiRequest(Token token) { return HttpRequest .newBuilder() .GET() .header(API_HEADER, API_VERSION) - .header(AUTH_HEADER, "token " + token); + .header(AUTH_HEADER, "token " + token.value()); } } From fa4b8ab36d6b0e52f32b46f7400842ff16de14a5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 15:17:28 +0300 Subject: [PATCH 393/492] Extract GoogleChatKey from Secrets. --- .../chatbot/api/google/chat/GoogleChat.java | 70 +----------------- .../api/google/chat/GoogleChatKey.java | 72 ++++++++++++++++++ .../api/google/chat/HangoutsChatProvider.java | 74 +++++++++++++++++++ .../secret/{Secrets.java => Secret.java} | 15 +--- .../io/spine/chatbot/api/travis/Token.java | 8 +- .../io/spine/chatbot/api/travis/Travis.java | 4 +- 6 files changed, 157 insertions(+), 86 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java rename google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/{Secrets.java => Secret.java} (84%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index cc85a7b7..8653b8fd 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -20,32 +20,22 @@ package io.spine.chatbot.api.google.chat; -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.chat.v1.HangoutsChat; import com.google.api.services.chat.v1.model.Message; -import com.google.auth.http.HttpCredentialsAdapter; -import com.google.auth.oauth2.GoogleCredentials; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.spine.chatbot.api.google.secret.Secrets; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.logging.Logging; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.security.GeneralSecurityException; import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; +import static io.spine.chatbot.api.google.chat.HangoutsChatProvider.newHangoutsChat; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; -import static io.spine.util.Exceptions.newIllegalStateException; /** * Google Chat API client. @@ -54,9 +44,6 @@ */ public final class GoogleChat implements GoogleChatClient, Logging { - private static final String BOT_NAME = "Spine Chat Bot"; - private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; - private final HangoutsChat chat; private GoogleChat(HangoutsChat chat) { @@ -69,7 +56,7 @@ private GoogleChat(HangoutsChat chat) { *

    The client is backed by {@link HangoutsChat} API. */ public static GoogleChatClient newInstance() { - return new GoogleChat(HangoutsChatProvider.newHangoutsChat()); + return new GoogleChat(newHangoutsChat()); } @Override @@ -109,57 +96,4 @@ private Message sendMessage(SpaceId space, Message message) { throw new RuntimeException("Unable to send message to space " + space, e); } } - - /** - * Provides fully-configured {@link HangoutsChat chat} client. - */ - private static class HangoutsChatProvider { - - /** - * Prevents direct instantiation of the utility class. - */ - private HangoutsChatProvider() { - } - - /** - * Creates a new instance of the {@link HangoutsChat} client. - */ - private static HangoutsChat newHangoutsChat() { - HttpCredentialsAdapter credentialsAdapter = newCredentialsHelper(); - var chat = chatWithCredentials(credentialsAdapter) - .setApplicationName(BOT_NAME) - .build(); - return chat; - } - - private static HttpCredentialsAdapter newCredentialsHelper() { - try { - var serviceAccount = Secrets.chatServiceAccount(); - var credentials = GoogleCredentials.fromStream(streamFrom(serviceAccount)) - .createScoped(CHAT_BOT_SCOPE); - return new HttpCredentialsAdapter(credentials); - } catch (IOException e) { - throw newIllegalStateException(e, "Unable to read GoogleCredentials."); - } - } - - private static HangoutsChat.Builder - chatWithCredentials(HttpCredentialsAdapter credentialsAdapter) { - var transport = newTrustedTransport(); - var jacksonFactory = JacksonFactory.getDefaultInstance(); - return new HangoutsChat.Builder(transport, jacksonFactory, credentialsAdapter); - } - - private static HttpTransport newTrustedTransport() { - try { - return GoogleNetHttpTransport.newTrustedTransport(); - } catch (GeneralSecurityException | IOException e) { - throw newIllegalStateException(e, "Unable to instantiate trusted transport."); - } - } - - private static InputStream streamFrom(String data) { - return new ByteArrayInputStream(data.getBytes(Charset.defaultCharset())); - } - } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java new file mode 100644 index 00000000..1f8eff4c --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java @@ -0,0 +1,72 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api.google.chat; + +import com.google.auth.oauth2.GoogleCredentials; +import io.spine.chatbot.api.google.secret.Secret; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import static io.spine.util.Exceptions.newIllegalStateException; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; + +/** + * A service account key configured for Google Chat. + */ +final class GoogleChatKey extends Secret { + + private static final String CHAT_BOT_SCOPE = "https://www.googleapis.com/auth/chat.bot"; + private static final String CHAT_SERVICE_ACCOUNT = "ChatServiceAccount"; + + private final String value; + + private GoogleChatKey(String value) { + this.value = value; + } + + /** + * Creates the Google Chat service account key. + */ + static GoogleChatKey chatServiceAccountKey() { + var value = checkNotEmptyOrBlank(retrieveSecret(CHAT_SERVICE_ACCOUNT)); + return new GoogleChatKey(value); + } + + /** + * Converts the key to respective scoped {@code GoogleCredentials}. + */ + GoogleCredentials toCredentials() { + try { + return GoogleCredentials + .fromStream(streamFrom(value)) + .createScoped(CHAT_BOT_SCOPE); + } catch (IOException e) { + throw newIllegalStateException(e, "Unable to read GoogleCredentials."); + } + } + + private static InputStream streamFrom(String data) { + return new ByteArrayInputStream(data.getBytes(Charset.defaultCharset())); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java new file mode 100644 index 00000000..5c9e75eb --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java @@ -0,0 +1,74 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.api.google.chat; + +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.chat.v1.HangoutsChat; +import com.google.auth.http.HttpCredentialsAdapter; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import static io.spine.chatbot.api.google.chat.GoogleChatKey.chatServiceAccountKey; +import static io.spine.util.Exceptions.newIllegalStateException; + +/** + * Provides fully-configured {@link HangoutsChat chat} client. + */ +final class HangoutsChatProvider { + + private static final String BOT_NAME = "Spine ChatBot"; + + /** + * Prevents direct instantiation of the utility class. + */ + private HangoutsChatProvider() { + } + + /** + * Creates a new instance of the {@link HangoutsChat} client. + */ + static HangoutsChat newHangoutsChat() { + var credentials = chatServiceAccountKey().toCredentials(); + var credentialsAdapter = new HttpCredentialsAdapter(credentials); + var chat = chatWithCredentials(credentialsAdapter) + .setApplicationName(BOT_NAME) + .build(); + return chat; + } + + private static HangoutsChat.Builder + chatWithCredentials(HttpCredentialsAdapter credentialsAdapter) { + var transport = newTrustedTransport(); + var jacksonFactory = JacksonFactory.getDefaultInstance(); + return new HangoutsChat.Builder(transport, jacksonFactory, credentialsAdapter); + } + + private static HttpTransport newTrustedTransport() { + try { + return GoogleNetHttpTransport.newTrustedTransport(); + } catch (GeneralSecurityException | IOException e) { + throw newIllegalStateException(e, "Unable to instantiate trusted transport."); + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java similarity index 84% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java rename to google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java index a0d3439c..7a6b9863 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secrets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java @@ -28,23 +28,14 @@ import static io.spine.util.Exceptions.newIllegalStateException; /** - * Utility for accessing application secrets stored in Google Secret Manager. + * A utility for accessing application secrets stored in Google Secret Manager. */ -public abstract class Secrets { +public abstract class Secret { @SuppressWarnings("CallToSystemGetenv") private static final String PROJECT_ID = System.getenv("GCP_PROJECT_ID"); - private static final String CHAT_SERVICE_ACCOUNT = "ChatServiceAccount"; - protected Secrets() { - } - - /** - * Retrieves the Google Chat API service account. - */ - public static String chatServiceAccount() { - var result = retrieveSecret(CHAT_SERVICE_ACCOUNT); - return result; + protected Secret() { } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java index f82ecb84..e0b17d42 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java @@ -20,14 +20,14 @@ package io.spine.chatbot.api.travis; -import io.spine.chatbot.api.google.secret.Secrets; +import io.spine.chatbot.api.google.secret.Secret; import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** - * A secret Travis CI API token. + * A Travis CI API access token. */ -final class Token extends Secrets { +final class Token extends Secret { private static final String TRAVIS_API_TOKEN = "TravisApiToken"; @@ -47,7 +47,7 @@ String value() { /** * Creates the Travis CI API access token. */ - static Token secretToken() { + static Token privateToken() { var value = checkNotEmptyOrBlank(retrieveSecret(TRAVIS_API_TOKEN)); return new Token(value); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index 1e4f2f0f..3c7b9691 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -27,7 +27,7 @@ import static com.google.api.client.util.Preconditions.checkNotNull; import static io.spine.chatbot.api.travis.JsonProtoBodyHandler.jsonBodyHandler; -import static io.spine.chatbot.api.travis.Token.secretToken; +import static io.spine.chatbot.api.travis.Token.privateToken; import static java.lang.String.format; /** @@ -56,7 +56,7 @@ private Travis(Token apiToken) { * Creates a new Travis client with the default Travis token. */ public static TravisClient newInstance() { - return new Travis(secretToken()); + return new Travis(privateToken()); } @Override From 7a83d85906ebaa08a5016aa9bcdc3a437fca6684 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 15:20:02 +0300 Subject: [PATCH 394/492] Add missing trailing empty line --- .idea/misc.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 425e8bb6..c2b0bbbe 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -62,4 +62,4 @@ - \ No newline at end of file + From a105b7920abb951e7170fbc20ebc406e2f3bdbb5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 15:48:27 +0300 Subject: [PATCH 395/492] Use standard ChatBot name --- google-chat-bot/src/main/java/io/spine/chatbot/Application.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index cbbeca02..f38c09db 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -37,7 +37,7 @@ import static io.spine.util.Exceptions.newIllegalStateException; /** - * The entry point to the Google Chat Bot application. + * The entry point to the Spine ChatBot application. * *

    The application itself exposes a number of REST endpoints accessible for the clients such as: * From 5845c91c948068c2d161ebe7981e05488c6a07ca Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 15:49:44 +0300 Subject: [PATCH 396/492] Rename `Stopped` to `ShutdownHook` and inline `server` variable --- .../main/java/io/spine/chatbot/Application.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index f38c09db..7ca3e02c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -21,7 +21,6 @@ package io.spine.chatbot; import com.google.common.annotations.VisibleForTesting; -import com.google.errorprone.annotations.concurrent.LazyInit; import io.micronaut.context.event.ApplicationEventListener; import io.micronaut.context.event.ShutdownEvent; import io.micronaut.runtime.Micronaut; @@ -29,7 +28,6 @@ import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.logging.Logging; import io.spine.server.Server; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import java.io.IOException; @@ -61,9 +59,6 @@ public final class Application implements Logging { /** Name of the GRPC {@link Server}. **/ static final String SERVER_NAME = "ChatBotServer"; - @LazyInit - private @MonotonicNonNull Server server; - /** * Prevents direct instantiation. */ @@ -98,10 +93,10 @@ private void start(String[] args) { .newBuilder() .build(); _config().log("Starting GRPC server."); - server = startServer(gitHubContext, googleChatContext); + var server = startServer(gitHubContext, googleChatContext); _config().log("Starting Micronaut application."); var applicationContext = Micronaut.run(Application.class, args); - applicationContext.registerSingleton(new Stopper(server)); + applicationContext.registerSingleton(new ShutdownHook(server)); } /** @@ -127,11 +122,12 @@ static Server startServer(GitHubContext gitHubContext, GoogleChatContext googleC /** * Gracefully stops the {@link #server}. */ - private static final class Stopper implements ApplicationEventListener, Logging { + private static final class ShutdownHook + implements ApplicationEventListener, Logging { private final Server server; - private Stopper(Server server) { + private ShutdownHook(Server server) { this.server = checkNotNull(server); } From 5e45da0d2b97a02b4fc2f4ab57bf169a2753ad47 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 15:50:41 +0300 Subject: [PATCH 397/492] Improve styling --- .../src/main/java/io/spine/chatbot/BeanFactory.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 1beb9c40..1f99824b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -57,8 +57,7 @@ PubsubPushRequestDeserializer pubsubDeserializer() { * Jackson Deserialization */ @VisibleForTesting - static final class PubsubPushRequestDeserializer - extends JsonDeserializer { + static final class PubsubPushRequestDeserializer extends JsonDeserializer { /** * Deserializes {@link PubsubPushRequest} JSON string into a Protobuf message. From a10335c6a1c6ac4bfc609c511566839bf136ac05 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 15:56:37 +0300 Subject: [PATCH 398/492] Improve docs --- .../io/spine/chatbot/api/travis/JsonProtoBodyHandler.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java index 7ebffdaa..5d77daee 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java @@ -31,8 +31,8 @@ import static com.google.common.base.Preconditions.checkNotNull; /** - * The handler converts input JSON strings into the Protobuf messages relying on the - * Spine {@link Json} conversion functionality. + * Converts the incoming JSON strings into Protobuf messages relying on the Spine + * {@link Json conversion functionality}. * * @param * the Protobuf message supplied in the response body @@ -49,8 +49,7 @@ private JsonProtoBodyHandler(Class type) { * Creates a body handler for a specified Protobuf message. */ static JsonProtoBodyHandler jsonBodyHandler(Class type) { - checkNotNull(type); - return new JsonProtoBodyHandler<>(type); + return new JsonProtoBodyHandler<>(checkNotNull(type)); } @Override From 2f11336991f1d3f223cf581989ee56f4c3202a93 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 16:18:05 +0300 Subject: [PATCH 399/492] Add missing EOL --- .../src/main/proto/spine/chatbot/google/chat/space.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 0160f772..45078212 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -54,4 +54,4 @@ message SpaceHeader { // The display name (only if the space is a room). string display_name = 3; -} \ No newline at end of file +} From a5f198b2dbe847425a2c6aa6d404d48932d0e8ba Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 16:19:48 +0300 Subject: [PATCH 400/492] Improve wording --- .../main/proto/spine/chatbot/google/chat/space_commands.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index d53e5ff6..7e561b93 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -33,7 +33,7 @@ option java_generate_equals_and_hash = true; import "spine/chatbot/google/chat/identifiers.proto"; import "spine/chatbot/google/chat/space.proto"; -// Register Chat space command. +// A request to register a Chat space. message RegisterSpace { option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; From 7c612c8bba73f521feb06a3413183653b6ae0b91 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 16:20:46 +0300 Subject: [PATCH 401/492] Use shorter (entity) option notation --- .../src/main/proto/spine/chatbot/google/chat/thread_chat.proto | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto index e48197c5..c5fa0890 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread_chat.proto @@ -38,8 +38,7 @@ import "spine/chatbot/google/chat/thread.proto"; // Acknowledges incoming events and publishes messages to a respective thread if needed. // message ThreadChat { - option (entity).kind = PROCESS_MANAGER; - option (entity).visibility = FULL; + option (entity) = {kind: PROCESS_MANAGER visibility: FULL}; ThreadId thread = 1; From 09b7639c4037957a548f71c5126dc8dd5445bd5e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 16:23:43 +0300 Subject: [PATCH 402/492] Use static import --- .../java/io/spine/chatbot/server/github/SlugMixinTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java index bd0a61e8..22fb9ac8 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java @@ -20,10 +20,11 @@ package io.spine.chatbot.server.github; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + @DisplayName("`SlugMixin` should") final class SlugMixinTest { @@ -31,6 +32,6 @@ final class SlugMixinTest { @DisplayName("encode slug value") void encodeSlugValue() { var slug = Slugs.create("TestOrganization/test-repository"); - Assertions.assertEquals("TestOrganization%2Ftest-repository", slug.encodedValue()); + assertEquals("TestOrganization%2Ftest-repository", slug.encodedValue()); } } From adb2f25a7501995b53d9ce107ce64187ff36b3c0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 16:25:23 +0300 Subject: [PATCH 403/492] Use domain-specific setup method name --- .../io/spine/chatbot/server/google/chat/SpaceAggregateTest.java | 2 +- .../spine/chatbot/server/google/chat/ThreadAggregateTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index fab82b91..a1b50681 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -90,7 +90,7 @@ void settingState() { final class RegisterOnAddedBot { @BeforeEach - void setUp() { + void addBotToSpace() { var chatEvent = ChatEvent .newBuilder() .setSpace(chatSpace()) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 203970c4..035c4f2f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -99,7 +99,7 @@ final class AddMessage { threadResource("spaces/qpojdwpiq1241/threads/qwdojp12"); @BeforeEach - void setUp() { + void createThreadAndMessage() { var threadCreated = ThreadCreated .newBuilder() .setThread(thread) From 3cb0d1fbf4999ceed90cb20eff7a5071f87308cf Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 17:40:43 +0300 Subject: [PATCH 404/492] Add note about using the undelivered messages. --- ENVIRONMENT.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index c59722d2..7f09b6b5 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -93,7 +93,8 @@ The bot requires the following Pub/Sub topics to be configured: For the topic, the `dead-incoming-bot-messages` [pull subscription][pull-subscription] that never expires is configured. - In case of an undelivered message, it could be pulled from the subscription. + In case of an undelivered message, it can be pulled from the subscription for the further + analysis and investigation. 3. `repository-checks` — the topic that delivers scheduled tasks to check the build state of the watched resources (see [Cloud Scheduler](#cloud-scheduler) section for details). From b03768d94e5f3e5a7a94f4d7b474770868fc3c7e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 1 Jul 2020 17:55:14 +0300 Subject: [PATCH 405/492] Clarify the Pub/Sub usage --- ENVIRONMENT.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index 7f09b6b5..d4766559 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -69,8 +69,10 @@ to the publishing [guide][publishing-guide] where the essential configurations a ## Pub/Sub The application is built with resilience in mind and even though it exposes some REST APIs, -it is not intended to handle to load directly. Instead, it relies on the Google [Pub/Sub][pubsub] -async messaging service to receive the incoming messages and then stream them into the app. +it is not intended to handle to load directly due to the security and performance considerations. +Instead, it relies on the Google [Pub/Sub][pubsub] async messaging service to receive +the incoming messages and then stream them into the app. The Pub/Sub uses dedicated IAM +configuration and is able to handle ultimate load at any pace. The bot requires the following Pub/Sub topics to be configured: From cf05b20843acf8e495d8da51bfb6b1ea7134a880 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:09:16 +0300 Subject: [PATCH 406/492] Change H2 to H1 --- ENVIRONMENT.md | 14 +++++++------- README.md | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index d4766559..21b01fe9 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -4,7 +4,7 @@ Cloud Environment setup The ChatBot application is working in the cloud environment on the Google Cloud Platform (GCP) and this document provides an overview of the currently configured environment. -## Cloud Run +# Cloud Run The [Cloud Run][cloud-run] is used as the main compute platform for the ChatBot application. Cloud Run is a managed serverless solution that works with Docker images and is able to scale @@ -22,7 +22,7 @@ new Cloud Run revision (see [Cloud Build](#cloud-build) section for details). [jib]: https://github.com/GoogleContainerTools/jib [container-registry]: https://cloud.google.com/container-registry -## Cloud Build +# Cloud Build The [Cloud Build][cloud-build] CI/CD solution is used to continuously build and deploy the application. @@ -46,7 +46,7 @@ configured to allow the Cloud Run deployment (see the [IAM](#iam) section for de [cloud-build-github-app]: https://github.com/marketplace/google-cloud-build [run-builds-on-github]: https://cloud.google.com/cloud-build/docs/automating-builds/run-builds-on-github -## Hangouts Chat API +# Hangouts Chat API The bot uses [Hangout Chat API][chat-api] and is linked to the GCP project. It is only possible to have a single bot per GCP project. @@ -66,7 +66,7 @@ to the publishing [guide][publishing-guide] where the essential configurations a [publishing-guide]: https://developers.google.com/hangouts/chat/how-tos/bots-publish [pubsub-bot]: https://developers.google.com/hangouts/chat/how-tos/pub-sub -## Pub/Sub +# Pub/Sub The application is built with resilience in mind and even though it exposes some REST APIs, it is not intended to handle to load directly due to the security and performance considerations. @@ -111,7 +111,7 @@ The bot requires the following Pub/Sub topics to be configured: [push-subscription]: https://cloud.google.com/pubsub/docs/push [pull-subscription]: https://cloud.google.com/pubsub/docs/pull -## Cloud Scheduler +# Cloud Scheduler The [Cloud Scheduler][scheduler] service allows configuring multiple scheduled tasks that deliver the payload to a particular target (HTTP endpoint, Pub/Sub topic or AppEngine endpoint). @@ -124,7 +124,7 @@ expression: `0 * * * *`. [scheduler]: https://cloud.google.com/scheduler [configure-schedules]: https://cloud.google.com/scheduler/docs/configuring/cron-job-schedules -## Secret Manager +# Secret Manager The [Secret Manager][secret-manager] service is used to supply application secrets like API tokens and service accounts securely. @@ -149,7 +149,7 @@ The following secrets are configured for the bot: [managing-secrets]: https://cloud.google.com/secret-manager/docs/managing-secrets [reading-secrets]: https://cloud.google.com/secret-manager/docs/managing-secret-versions#get -## IAM +# IAM The [Cloud Identity and Access Management][iam] (IAM) service is used to fine-tune the authorization and access management for the application. diff --git a/README.md b/README.md index e66e675e..bc8beb48 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ via the [Google Chat][google-chat]. [chatbot-concepts]: https://developers.google.com/hangouts/chat/concepts/bots [google-chat]: https://chat.google.com/ -## Prerequisites +# Prerequisites * [JDK 11][jdk11] or newer. * [Docker SE][docker] v19.03 or newer. @@ -16,7 +16,7 @@ via the [Google Chat][google-chat]. [docker]: https://docs.docker.com/get-docker/ [jdk11]: https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html -## Build +# Build In order to build the application, run: @@ -32,7 +32,7 @@ Also, it is possible to build a Docker image using [`jib`][jib]: [jib]: https://github.com/GoogleContainerTools/jib -## Running locally +# Running locally It is possible to run the application as a docker image locally. In order to do that, please make sure you have saved the appropriate GCP credentials at `.credentials/gcp-adc.json`. @@ -65,7 +65,7 @@ Cloud Run [guide][cloud-run-local-guide]. [cloud-run-local-guide]: https://cloud.google.com/run/docs/testing/local#running_locally_using_docker_with_access_to_services -## Running in the Cloud +# Running in the Cloud The application is deployed in the Google Cloud Platform cloud, and the overview of the cloud deployment is available in a separate [document](ENVIRONMENT.md). From eeddf1b22234510736ad602016edca7dbee0246c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:11:17 +0300 Subject: [PATCH 407/492] Use context name from the constant --- .../java/io/spine/chatbot/IncomingEventsController.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index b7aa3abc..ae5307d5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -42,8 +42,9 @@ @Controller("/chat") final class IncomingEventsController implements Logging { + private static final String INCOMING_EVENTS_CONTEXT_NAME = "IncomingChatEvents"; private static final ThirdPartyContext INCOMING_EVENTS = - ThirdPartyContext.singleTenant("IncomingChatEvents"); + ThirdPartyContext.singleTenant(INCOMING_EVENTS_CONTEXT_NAME); /** * Processes an incoming Google Chat event. @@ -78,12 +79,12 @@ private static UserId eventActor(User user) { */ @EventListener void on(ShutdownEvent event) { - _info().log("Closing IncomingChatEvents third-party context."); + _info().log("Closing `%s` third-party context.", INCOMING_EVENTS_CONTEXT_NAME); try { INCOMING_EVENTS.close(); } catch (Exception e) { _error().withCause(e) - .log("Unable to gracefully close IncomingChatEvents context."); + .log("Unable to gracefully close `%s` context.", INCOMING_EVENTS_CONTEXT_NAME); } } } From b1208a9ac0a96cc7865f71042fb110b4d494d28c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:12:20 +0300 Subject: [PATCH 408/492] Use command name from the class instance --- .../main/java/io/spine/chatbot/RepositoriesController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 2c9eacc7..2d7f39e1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -55,8 +55,8 @@ String checkBuildStatuses() { private void checkBuildStatus(Client client, RepositoryId repository, Organization organization) { - _info().log("Sending `CheckRepositoryBuild` command for the repository `%s`.", - repository.getValue()); + _info().log("Sending `%s` command for the repository `%s`.", + CheckRepositoryBuild.class.getSimpleName(), repository.getValue()); var checkRepositoryBuild = checkRepoBuildCommand(repository, organization); client.post(checkRepositoryBuild); } From d3380439d43543ddb1265e82407898c91d66a4b4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:13:49 +0300 Subject: [PATCH 409/492] Drop logging and use a more specific exception --- .../java/io/spine/chatbot/api/google/chat/GoogleChat.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index 8653b8fd..d4a208f5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -36,6 +36,7 @@ import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; +import static io.spine.util.Exceptions.newIllegalStateException; /** * Google Chat API client. @@ -91,9 +92,7 @@ private Message sendMessage(SpaceId space, Message message) { .create(space.getValue(), message) .execute(); } catch (IOException e) { - _error().withCause(e) - .log("Unable to send message to space `%s`.", space); - throw new RuntimeException("Unable to send message to space " + space, e); + throw newIllegalStateException(e, "Unable to send message to the space `%s`.", space); } } } From 1cd6ca1c3c915071237f2f9130a886172e0fd8d1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:14:29 +0300 Subject: [PATCH 410/492] Backtick `GoogleCredentials` in exception message --- .../java/io/spine/chatbot/api/google/chat/GoogleChatKey.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java index 1f8eff4c..85ccc25f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java @@ -62,7 +62,7 @@ GoogleCredentials toCredentials() { .fromStream(streamFrom(value)) .createScoped(CHAT_BOT_SCOPE); } catch (IOException e) { - throw newIllegalStateException(e, "Unable to read GoogleCredentials."); + throw newIllegalStateException(e, "Unable to read `GoogleCredentials`."); } } From cf28d179f172628266fb2b1c8fc09e2a1a5f677e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:15:46 +0300 Subject: [PATCH 411/492] Improve class-level doc wording. --- .../main/java/io/spine/chatbot/api/google/secret/Secret.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java index 7a6b9863..d8bfe784 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java @@ -28,7 +28,7 @@ import static io.spine.util.Exceptions.newIllegalStateException; /** - * A utility for accessing application secrets stored in Google Secret Manager. + * The abstract base for utilities that access application secrets stored in Google Secret Manager. */ public abstract class Secret { From 379230d559b36631cc4f9fc38c2e37f3a218d2d2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:19:07 +0300 Subject: [PATCH 412/492] Hide Travis and GoogleChat implementations. --- .../spine/chatbot/api/google/chat/GoogleChat.java | 14 ++------------ .../chatbot/api/google/chat/GoogleChatClient.java | 12 ++++++++++++ .../java/io/spine/chatbot/api/travis/Travis.java | 12 ++---------- .../io/spine/chatbot/api/travis/TravisClient.java | 9 +++++++++ .../spine/chatbot/server/github/GitHubContext.java | 5 ++--- .../server/google/chat/GoogleChatContext.java | 3 +-- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index d4a208f5..e919661a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -32,7 +32,6 @@ import java.io.IOException; import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; -import static io.spine.chatbot.api.google.chat.HangoutsChatProvider.newHangoutsChat; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @@ -43,23 +42,14 @@ * * @see Google Chat API */ -public final class GoogleChat implements GoogleChatClient, Logging { +final class GoogleChat implements GoogleChatClient, Logging { private final HangoutsChat chat; - private GoogleChat(HangoutsChat chat) { + GoogleChat(HangoutsChat chat) { this.chat = chat; } - /** - * Creates a new Google Chat client. - * - *

    The client is backed by {@link HangoutsChat} API. - */ - public static GoogleChatClient newInstance() { - return new GoogleChat(newHangoutsChat()); - } - @Override public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { var repo = build.getRepository(); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java index b1e2b466..a3932487 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java @@ -20,10 +20,13 @@ package io.spine.chatbot.api.google.chat; +import com.google.api.services.chat.v1.HangoutsChat; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.thread.ThreadResource; +import static io.spine.chatbot.api.google.chat.HangoutsChatProvider.newHangoutsChat; + /** * Google Chat API client abstraction. * @@ -40,4 +43,13 @@ public interface GoogleChatClient { * @return a sent build state update message */ BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread); + + /** + * Creates a new Google Chat client. + * + *

    The client is backed by {@link HangoutsChat} API. + */ + static GoogleChatClient newInstance() { + return new GoogleChat(newHangoutsChat()); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java index 3c7b9691..2607ff36 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java @@ -27,7 +27,6 @@ import static com.google.api.client.util.Preconditions.checkNotNull; import static io.spine.chatbot.api.travis.JsonProtoBodyHandler.jsonBodyHandler; -import static io.spine.chatbot.api.travis.Token.privateToken; import static java.lang.String.format; /** @@ -35,7 +34,7 @@ * * @see Travis CI API */ -public final class Travis implements TravisClient { +final class Travis implements TravisClient { private static final HttpClient CLIENT = HttpClient.newHttpClient(); private static final String BASE_URL = "https://api.travis-ci.com"; @@ -48,17 +47,10 @@ public final class Travis implements TravisClient { /** * Creates a new Travis client with the specified API token. */ - private Travis(Token apiToken) { + Travis(Token apiToken) { this.apiToken = checkNotNull(apiToken); } - /** - * Creates a new Travis client with the default Travis token. - */ - public static TravisClient newInstance() { - return new Travis(privateToken()); - } - @Override public T execute(Query query) { var result = execute(query.request(), query.responseType()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java index 2d5bb665..a74ff84f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java @@ -20,6 +20,8 @@ package io.spine.chatbot.api.travis; +import static io.spine.chatbot.api.travis.Token.privateToken; + /** * A Travis CI API client. * @@ -37,4 +39,11 @@ public interface TravisClient { * @return query execution result */ T execute(Query query); + + /** + * Creates a new Travis client with the default Travis token. + */ + static TravisClient newInstance() { + return new Travis(privateToken()); + } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 7e9845aa..b8a0ea1e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -20,7 +20,6 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.Travis; import io.spine.chatbot.api.travis.TravisClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -92,11 +91,11 @@ public Builder setTravis(TravisClient client) { * Finishes configuration of the context and builds a new instance. * *

    If the {@link #client} was not explicitly configured, uses the - * {@link Travis#newInstance() default} client. + * {@link TravisClient#newInstance() default} client. */ public GitHubContext build() { if (client == null) { - client = Travis.newInstance(); + client = TravisClient.newInstance(); } return new GitHubContext(client); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 46a91012..43604f0e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -20,7 +20,6 @@ package io.spine.chatbot.server.google.chat; -import io.spine.chatbot.api.google.chat.GoogleChat; import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -94,7 +93,7 @@ public Builder setClient(GoogleChatClient client) { */ public GoogleChatContext build() { if (client == null) { - client = GoogleChat.newInstance(); + client = GoogleChatClient.newInstance(); } return new GoogleChatContext(client); } From ddd2541822b02d599d4e0548b8c35257ffdfa0b9 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:20:05 +0300 Subject: [PATCH 413/492] Improve logs wording --- .../spine/chatbot/server/google/chat/ThreadChatProcess.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index ab68a375..ce285ecc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -57,7 +57,7 @@ Pair> on(@External BuildFailed e) { var change = e.getChange(); var build = change.getNewValue(); var repository = e.getRepository(); - _info().log("Build for repository `%s` failed.", repository.getValue()); + _info().log("A build for the repository `%s` failed.", repository.getValue()); return processBuildStateUpdate(build, repository); } @@ -72,7 +72,7 @@ Pair> on(@External BuildRecovered e) { var change = e.getChange(); var build = change.getNewValue(); var repository = e.getRepository(); - _info().log("Build for repository `%s` recovered.", repository.getValue()); + _info().log("A build for the repository `%s` recovered.", repository.getValue()); return processBuildStateUpdate(build, repository); } @@ -89,7 +89,7 @@ Pair> on(@External BuildRecovered e) { .vBuild(); if (shouldCreateThread()) { var resource = sentUpdate.getResource(); - _debug().log("New thread `%s` created for repository `%s`.", + _debug().log("A new thread `%s` created for the repository `%s`.", resource.getName(), repository.getValue()); builder().setResource(resource) .setSpace(space); From 75df07118a1cb30fda2cebd8468f4906b678174a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:22:48 +0300 Subject: [PATCH 414/492] Use singular for repeated fields as per the Spine convention. See https://github.com/SpineEventEngine/core-java/wiki/Protobuf-Code-Style#naming-repeated-and-map-fields for details. --- .../src/main/java/io/spine/chatbot/client/Client.java | 2 +- .../io/spine/chatbot/server/github/OrgReposProjection.java | 6 +++--- .../spine/chatbot/github/organization_repositories.proto | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index 62157085..6e31e64a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -81,7 +81,7 @@ public ImmutableList listOrgRepos(OrganizationId org) { .run(); checkState(orgRepos.size() == 1); return ImmutableList.copyOf(orgRepos.get(0) - .getRepositoriesList()); + .getRepositoryList()); } @Override diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java index 053df79e..58f1739c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java @@ -51,9 +51,9 @@ void on(OrganizationRegistered e) { */ @Subscribe void on(RepositoryRegistered e) { - var repositories = Sets.newHashSet(builder().getRepositoriesList()); + var repositories = Sets.newHashSet(builder().getRepositoryList()); repositories.add(e.getRepository()); - builder().clearRepositories() - .addAllRepositories(repositories); + builder().clearRepository() + .addAllRepository(repositories); } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto index 501d53be..0f366192 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_repositories.proto @@ -39,5 +39,5 @@ message OrganizationRepositories { OrganizationId organization = 1; // Linked organization repositories. - repeated RepositoryId repositories = 2; + repeated RepositoryId repository = 2; } From 5bb1144157e474d2bae0d7ab827372f666b1db54 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:25:07 +0300 Subject: [PATCH 415/492] Use Exceptions utility instead of direct RuntimeException --- .../src/main/java/io/spine/chatbot/client/Client.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index 6e31e64a..bb27c968 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -123,7 +123,7 @@ public void post(CommandMessage command) { try { latch.await(); } catch (InterruptedException e) { - throw new RuntimeException("Processing of command failed. Command: " + command, e); + newIllegalStateException(e, "Processing of command interrupted: %s.", command); } subscriptions.forEach(this::cancelSubscription); } From 4ae3997aa804d99c3442c38f841d0d21a1b53b54 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:26:06 +0300 Subject: [PATCH 416/492] Extract `trace` logger --- .../io/spine/chatbot/delivery/ShardDelivery.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java index 95a8958b..3478c364 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -58,21 +58,21 @@ static void deliverFrom(ShardIndex shard) { } private void deliverNow() { + var trace = _trace(); var server = ServerEnvironment.instance(); var nodeId = server.nodeId() .getValue(); var indexValue = shard.getIndex(); - _trace().log("Delivering messages from shard with index `%d`. NodeId=%s.", - indexValue, nodeId); + trace.log("Delivering messages from shard with index `%d`. NodeId=%s.", indexValue, nodeId); var stats = server.delivery() .deliverMessagesFrom(shard); if (stats.isPresent()) { DeliveryStats deliveryStats = stats.get(); - _trace().log("`%d` messages delivered from shard with index `%s`. NodeId=%s.", - deliveryStats.deliveredCount(), indexValue, nodeId); + trace.log("`%d` messages delivered from shard with index `%s`. NodeId=%s.", + deliveryStats.deliveredCount(), indexValue, nodeId); } else { - _trace().log("No messages delivered from shard with index `%d`. NodeId=%s.", - indexValue, nodeId); + trace.log("No messages delivered from shard with index `%d`. NodeId=%s.", + indexValue, nodeId); } } } From 14f667dd7f48930dd87e4079cf8fc8114b5c28c8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:28:35 +0300 Subject: [PATCH 417/492] Improve logs wording. --- .../io/spine/chatbot/server/github/RepoBuildProcess.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 6d9ea2aa..cb923c49 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -119,14 +119,15 @@ EitherOf3 handle(CheckReposito case UNRECOGNIZED: default: throw newIllegalStateException( - "Unexpected state status change `%s`.", stateStatusChange + "Unexpected state status change `%s` for the repository `%s`.", + stateStatusChange, repository.getValue() ); } } private EitherOf3 onStable(RepositoryId repository, BuildStateChange stateChange) { - _info().log("Build for the repository `%s` is stable.", repository.getValue()); + _info().log("The build for the repository `%s` is stable.", repository.getValue()); var buildSucceededAgain = BuildSucceededAgain .newBuilder() .setRepository(repository) @@ -137,7 +138,7 @@ EitherOf3 handle(CheckReposito private EitherOf3 onRecovered(RepositoryId repository, BuildStateChange stateChange) { - _info().log("Build for the repository `%s` is recovered.", repository.getValue()); + _info().log("The build for the repository `%s` is recovered.", repository.getValue()); var buildRecovered = BuildRecovered .newBuilder() .setRepository(repository) @@ -149,7 +150,7 @@ EitherOf3 handle(CheckReposito private EitherOf3 onFailed(RepositoryId repository, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); - _info().log("Build for the repository `%s` failed with status `%s`.", + _info().log("A build for the repository `%s` failed with the status `%s`.", repository.getValue(), newBuildState.getState()); var buildFailed = BuildFailed .newBuilder() From 92cb68505f05c5ca6c83d554829e4dfd2381f710 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:34:21 +0300 Subject: [PATCH 418/492] Improve logging and make it easier to differentiate which method is called --- .../spine/chatbot/server/google/chat/SpaceAggregate.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java index 25ebe5ea..41b0d8fa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceAggregate.java @@ -48,7 +48,8 @@ SpaceRegistered on(BotAddedToSpace e) { .getSpace(); var displayName = space.getDisplayName(); var spaceId = e.getSpace(); - _info().log("Registering space `%s` (`%s`).", displayName, spaceId.getValue()); + _info().log("Registering the space `%s` (`%s`) because the bot is added the space.", + displayName, spaceId.getValue()); var header = SpaceHeader .newBuilder() .setDisplayName(displayName) @@ -66,12 +67,14 @@ SpaceRegistered on(BotAddedToSpace e) { */ @Assign SpaceRegistered handle(RegisterSpace c) { + var header = c.getHeader(); var space = c.getId(); - _info().log("Registering space `%s`.", space.getValue()); + _info().log("Registering the space `%s` (`%s`) on direct registration request.", + header.getDisplayName(), space.getValue()); var result = SpaceRegistered .newBuilder() .setSpace(space) - .setHeader(c.getHeader()) + .setHeader(header) .vBuild(); return result; } From 78f9fbed660a1cc5dc8222bc778955b010db2f2f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:38:59 +0300 Subject: [PATCH 419/492] Improve logs --- .../google/chat/IncomingEventsHandler.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index ddfc9a69..738b06e4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -32,6 +32,10 @@ import io.spine.server.model.Nothing; import io.spine.server.tuple.EitherOf4; +import static io.spine.chatbot.server.google.chat.ChatEvents.toBotAddedToSpace; +import static io.spine.chatbot.server.google.chat.ChatEvents.toBotRemovedFromSpace; +import static io.spine.chatbot.server.google.chat.ChatEvents.toMessageReceived; + /** * Google Chat incoming events reactor. * @@ -58,28 +62,27 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin EitherOf4 on(@External ChatEventReceived e) { var chatEvent = e.getEvent(); + var space = chatEvent.getSpace(); switch (chatEvent.getType()) { case MESSAGE: - _info().log("New user message received."); - return EitherOf4.withC(ChatEvents.toMessageReceived(chatEvent)); + _info().log("A new user message received in the space `%s` (%s).", + space.getDisplayName(), space.getName()); + return EitherOf4.withC(toMessageReceived(chatEvent)); case ADDED_TO_SPACE: - var toSpace = chatEvent.getSpace(); - _info().log("ChatBot added to space `%s` (%s).", - toSpace.getDisplayName(), toSpace.getName()); - return EitherOf4.withA(ChatEvents.toBotAddedToSpace(chatEvent)); + _info().log("ChatBot added to the space `%s` (%s).", + space.getDisplayName(), space.getName()); + return EitherOf4.withA(toBotAddedToSpace(chatEvent)); case REMOVED_FROM_SPACE: - var fromSpace = chatEvent.getSpace(); - _info().log("ChatBot removed from space `%s` (%s).", - fromSpace.getDisplayName(), fromSpace.getName()); - return EitherOf4.withB(ChatEvents.toBotRemovedFromSpace(chatEvent)); - + _info().log("ChatBot removed from the space `%s` (%s).", + space.getDisplayName(), space.getName()); + return EitherOf4.withB(toBotRemovedFromSpace(chatEvent)); case CARD_CLICKED: _debug().log("Skipping card clicks."); return EitherOf4.withD(nothing()); case UNRECOGNIZED: case ET_UNKNOWN: default: - _error().log("Unsupported chat event type received: %s", chatEvent.getType()); + _error().log("Unsupported chat event type received: `%s`.", chatEvent.getType()); return EitherOf4.withD(nothing()); } } From 032397af3e0317227b76a55d89048da89ec9790d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:40:48 +0300 Subject: [PATCH 420/492] Add missing articles --- .../java/io/spine/chatbot/api/google/chat/GoogleChat.java | 6 +++--- .../main/java/io/spine/chatbot/delivery/ShardDelivery.java | 7 ++++--- .../spine/chatbot/server/github/SpineOrgInitProcess.java | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java index e919661a..7114e4d5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java @@ -54,12 +54,12 @@ final class GoogleChat implements GoogleChatClient, Logging { public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { var repo = build.getRepository(); var debug = _debug(); - debug.log("Building state update message for repository `%s`.", repo); + debug.log("Building state update message for the repository `%s`.", repo); var message = buildStateMessage(build, thread); - debug.log("Sending state update message for repository `%s`.", repo); + debug.log("Sending state update message for the repository `%s`.", repo); var sentMessage = sendMessage(build.getSpace(), message); debug.log( - "Build state update message with ID `%s` for repository `%s` sent to thread `%s`.", + "Build state update message with ID `%s` for the repository `%s` sent to the thread `%s`.", sentMessage.getName(), repo, sentMessage.getThread() .getName() ); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java index 3478c364..3f073588 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -63,15 +63,16 @@ private void deliverNow() { var nodeId = server.nodeId() .getValue(); var indexValue = shard.getIndex(); - trace.log("Delivering messages from shard with index `%d`. NodeId=%s.", indexValue, nodeId); + trace.log("Delivering messages from the shard with index `%d`. NodeId=%s.", indexValue, + nodeId); var stats = server.delivery() .deliverMessagesFrom(shard); if (stats.isPresent()) { DeliveryStats deliveryStats = stats.get(); - trace.log("`%d` messages delivered from shard with index `%s`. NodeId=%s.", + trace.log("`%d` messages delivered from the shard with index `%s`. NodeId=%s.", deliveryStats.deliveredCount(), indexValue, nodeId); } else { - trace.log("No messages delivered from shard with index `%d`. NodeId=%s.", + trace.log("No messages delivered from the shard with index `%d`. NodeId=%s.", indexValue, nodeId); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 5214fe57..76cc5f25 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -81,7 +81,7 @@ Iterable on(@External SpaceRegistered e) { return ImmutableSet.of(); } var space = e.getSpace(); - _info().log("Starting Spine organization initialization process in space `%s`.", space); + _info().log("Starting Spine organization initialization process in the space `%s`.", space); var commands = ImmutableSet.builder(); commands.add(registerOrgCommand(ORGANIZATION, space)); client.execute(ReposQuery.forOwner(Slugs.forOrg(ORGANIZATION))) From 874657ed7d767bfcd6017b4bf9d69514c7bcdf1d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 13:46:14 +0300 Subject: [PATCH 421/492] Add link to the Secret Manager --- .../main/java/io/spine/chatbot/api/google/secret/Secret.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java index d8bfe784..983aec96 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java @@ -29,6 +29,8 @@ /** * The abstract base for utilities that access application secrets stored in Google Secret Manager. + * + * @see Google Secret Manager */ public abstract class Secret { From 48a13119c0c7811a6022191e4a27114d501e6e07 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Mon, 13 Jul 2020 21:52:11 +0300 Subject: [PATCH 422/492] Add new repo only we do not have it yet. --- .../server/github/OrgReposProjection.java | 16 +- .../server/github/OrgReposProjectionTest.java | 187 ++++++++++++++++++ 2 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java index 58f1739c..435fe6b8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgReposProjection.java @@ -20,8 +20,8 @@ package io.spine.chatbot.server.github; -import com.google.common.collect.Sets; import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.chatbot.github.organization.event.OrganizationRegistered; import io.spine.chatbot.github.repository.event.RepositoryRegistered; @@ -51,9 +51,15 @@ void on(OrganizationRegistered e) { */ @Subscribe void on(RepositoryRegistered e) { - var repositories = Sets.newHashSet(builder().getRepositoryList()); - repositories.add(e.getRepository()); - builder().clearRepository() - .addAllRepository(repositories); + var newRepo = e.getRepository(); + if (!hasRepository(newRepo)) { + builder().addRepository(newRepo); + } + } + + private boolean hasRepository(RepositoryId repo) { + return builder() + .getRepositoryList() + .contains(repo); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java new file mode 100644 index 00000000..66d6e943 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -0,0 +1,187 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server.github; + +import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.organization.OrgHeader; +import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.chatbot.github.organization.command.RegisterOrganization; +import io.spine.chatbot.github.repository.RepoHeader; +import io.spine.chatbot.github.repository.command.RegisterRepository; +import io.spine.chatbot.google.chat.SpaceId; +import io.spine.net.Url; +import io.spine.net.Urls; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.server.github.GitHubIdentifier.organization; +import static io.spine.chatbot.server.github.GitHubIdentifier.repository; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.url.MoreUrls.githubUrlFor; +import static io.spine.chatbot.url.MoreUrls.travisUrlFor; + +@DisplayName("`OrgReposProjection` should") +final class OrgReposProjectionTest extends GitHubContextAwareTest { + + @Nested + @DisplayName("register an organization") + final class RegisterOrg { + + private static final String orgName = "Our Org"; + + private final SpaceId googleChatSpace = space("spaces/qwdp123tt1"); + private final OrganizationId organization = organization("OurOrg"); + + private final Url githubUrl = githubUrlFor(organization.getValue()); + private final Url travisCiUrl = travisUrlFor(organization.getValue()); + private final Url websiteUrl = Urls.create("https://our-organization.com"); + + private final OrgHeader header = OrgHeader + .newBuilder() + .setGithubProfile(githubUrl) + .setTravisProfile(travisCiUrl) + .setWebsite(websiteUrl) + .setName(orgName) + .setSpace(googleChatSpace) + .vBuild(); + + @BeforeEach + void registerOrg() { + var registerOrganization = RegisterOrganization + .newBuilder() + .setId(organization) + .setHeader(header) + .vBuild(); + context().receivesCommand(registerOrganization); + } + + @Test + @DisplayName("setting organization to the state") + void settingState() { + var expectedState = OrganizationRepositories + .newBuilder() + .setOrganization(organization) + .vBuild(); + context().assertState(organization, OrganizationRepositories.class) + .isEqualTo(expectedState); + } + } + + @Nested + @DisplayName("register repositories") + final class RegisterRepo { + + private static final String orgName = "Multi Repo Org"; + + private final SpaceId googleChatSpace = space("spaces/qqwp123ttQ"); + private final OrganizationId organization = organization("MultiRepoOrg"); + private final RepositoryId repository = repository("main-repo"); + + private final Url githubUrl = githubUrlFor(organization.getValue()); + private final Url travisCiUrl = travisUrlFor(organization.getValue()); + private final Url websiteUrl = Urls.create("https://multi-repo-organization.com"); + + private final OrgHeader orgHeader = OrgHeader + .newBuilder() + .setGithubProfile(githubUrl) + .setTravisProfile(travisCiUrl) + .setWebsite(websiteUrl) + .setName(orgName) + .setSpace(googleChatSpace) + .vBuild(); + + private final RepoHeader repoHeader = RepoHeader + .newBuilder() + .setGithubProfile(githubUrl) + .setTravisProfile(travisCiUrl) + .setName("Main Repo") + .setOrganization(organization) + .vBuild(); + + @BeforeEach + void registerOrg() { + var registerOrganization = RegisterOrganization + .newBuilder() + .setId(organization) + .setHeader(orgHeader) + .vBuild(); + context().receivesCommand(registerOrganization); + } + + @Test + @DisplayName("setting repository to the state") + void settingState() { + var registerRepository = RegisterRepository + .newBuilder() + .setId(repository) + .setHeader(repoHeader) + .vBuild(); + context().receivesCommand(registerRepository); + var expectedState = OrganizationRepositories + .newBuilder() + .setOrganization(organization) + .addRepository(repository) + .vBuild(); + context().assertState(organization, OrganizationRepositories.class) + .isEqualTo(expectedState); + } + + @Test + @DisplayName("handling duplicate repos gracefully") + void handleDuplicateRepos() { + var registerRepository = RegisterRepository + .newBuilder() + .setId(repository) + .setHeader(repoHeader) + .vBuild(); + context().receivesCommand(registerRepository); + context().receivesCommand(registerRepository); + var expectedState = OrganizationRepositories + .newBuilder() + .setOrganization(organization) + .addRepository(repository) + .vBuild(); + context().assertState(organization, OrganizationRepositories.class) + .isEqualTo(expectedState); + } + + @Test + @DisplayName("ignoring repos without organization") + void ignoreRepoWithoutOrg() { + var registerRepository = RegisterRepository + .newBuilder() + .setId(repository) + .setHeader(repoHeader.toBuilder() + .clearOrganization()) + .vBuild(); + context().receivesCommand(registerRepository); + var expectedState = OrganizationRepositories + .newBuilder() + .setOrganization(organization) + .vBuild(); + context().assertState(organization, OrganizationRepositories.class) + .isEqualTo(expectedState); + } + } +} From a9f77537a47868ceedbb711783dc7ce002fe49c5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 13:30:45 +0300 Subject: [PATCH 423/492] Drop `api` package. --- .../io/spine/chatbot/api/package-info.java | 30 ------------------- .../google/chat/BuildStateUpdates.java | 10 +++---- .../{api => }/google/chat/ChatWidgets.java | 2 +- .../{api => }/google/chat/GoogleChat.java | 6 ++-- .../google/chat/GoogleChatClient.java | 5 ++-- .../{api => }/google/chat/GoogleChatKey.java | 4 +-- .../google/chat/HangoutsChatProvider.java | 4 +-- .../{api => }/google/chat/package-info.java | 4 +-- .../{api => }/google/secret/Secret.java | 2 +- .../{api => }/google/secret/package-info.java | 2 +- .../chatbot/server/github/GitHubContext.java | 2 +- .../server/github/RepoBuildProcess.java | 4 +-- .../server/github/RepoBuildRepository.java | 2 +- .../server/github/SpineOrgInitProcess.java | 4 +-- .../server/github/SpineOrgInitRepository.java | 2 +- .../server/google/chat/GoogleChatContext.java | 2 +- .../server/google/chat/ThreadChatProcess.java | 2 +- .../google/chat/ThreadChatRepository.java | 2 +- .../chatbot/{api => }/travis/BuildsQuery.java | 3 +- .../travis/JsonProtoBodyHandler.java | 2 +- .../spine/chatbot/{api => }/travis/Query.java | 2 +- .../chatbot/{api => }/travis/ReposQuery.java | 3 +- .../spine/chatbot/{api => }/travis/Token.java | 4 +-- .../chatbot/{api => }/travis/Travis.java | 4 +-- .../{api => }/travis/TravisClient.java | 4 +-- .../{api => }/travis/TravisResponse.java | 2 +- .../{api => }/travis/package-info.java | 2 +- .../{api => }/FailFastAwareClient.java | 2 +- .../chatbot/IncomingEventsControllerTest.java | 4 +-- .../google/chat/BuildStateUpdatesTest.java | 2 +- .../google/chat/ChatWidgetsTest.java | 2 +- .../google/chat/InMemoryGoogleChatClient.java | 5 ++-- .../server/github/GitHubContextAwareTest.java | 2 +- .../server/github/GitHubContextTest.java | 2 +- .../chat/GoogleChatContextAwareTest.java | 2 +- .../google/chat/GoogleChatContextTest.java | 2 +- .../travis/InMemoryTravisClient.java | 6 ++-- 37 files changed, 57 insertions(+), 87 deletions(-) delete mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/BuildStateUpdates.java (93%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/ChatWidgets.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/GoogleChat.java (93%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/GoogleChatClient.java (91%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/GoogleChatKey.java (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/HangoutsChatProvider.java (95%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/chat/package-info.java (91%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/secret/Secret.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/google/secret/package-info.java (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/BuildsQuery.java (95%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/JsonProtoBodyHandler.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/Query.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/ReposQuery.java (95%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/Token.java (94%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/Travis.java (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/TravisClient.java (94%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/TravisResponse.java (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/{api => }/travis/package-info.java (97%) rename google-chat-bot/src/test/java/io/spine/chatbot/{api => }/FailFastAwareClient.java (99%) rename google-chat-bot/src/test/java/io/spine/chatbot/{api => }/google/chat/BuildStateUpdatesTest.java (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/{api => }/google/chat/ChatWidgetsTest.java (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/{api => }/google/chat/InMemoryGoogleChatClient.java (95%) rename google-chat-bot/src/test/java/io/spine/chatbot/{api => }/travis/InMemoryTravisClient.java (94%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java deleted file mode 100644 index b15f8cd4..00000000 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/package-info.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020, TeamDev. All rights reserved. - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * This package contains server-side reusable APIs. - */ -@CheckReturnValue -@ParametersAreNonnullByDefault -package io.spine.chatbot.api; - -import com.google.errorprone.annotations.CheckReturnValue; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java similarity index 93% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java index de4906c1..48b9aa3e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.api.services.chat.v1.model.CardHeader; import com.google.api.services.chat.v1.model.KeyValue; @@ -31,10 +31,10 @@ import io.spine.chatbot.google.chat.thread.ThreadResource; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.chatbot.api.google.chat.ChatWidgets.cardWith; -import static io.spine.chatbot.api.google.chat.ChatWidgets.linkButton; -import static io.spine.chatbot.api.google.chat.ChatWidgets.sectionWithWidget; -import static io.spine.chatbot.api.google.chat.ChatWidgets.textParagraph; +import static io.spine.chatbot.google.chat.ChatWidgets.cardWith; +import static io.spine.chatbot.google.chat.ChatWidgets.linkButton; +import static io.spine.chatbot.google.chat.ChatWidgets.sectionWithWidget; +import static io.spine.chatbot.google.chat.ChatWidgets.textParagraph; import static io.spine.protobuf.Messages.isNotDefault; import static io.spine.validate.Validate.checkValid; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java index d28c78c3..bbb77221 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/ChatWidgets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.api.services.chat.v1.model.Button; import com.google.api.services.chat.v1.model.Card; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java similarity index 93% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java index 7114e4d5..2ca388c8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java @@ -18,20 +18,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.api.services.chat.v1.HangoutsChat; import com.google.api.services.chat.v1.model.Message; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.spine.chatbot.github.repository.build.Build; -import io.spine.chatbot.google.chat.BuildStateUpdate; -import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.thread.ThreadResource; import io.spine.logging.Logging; import java.io.IOException; -import static io.spine.chatbot.api.google.chat.BuildStateUpdates.buildStateMessage; +import static io.spine.chatbot.google.chat.BuildStateUpdates.buildStateMessage; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java similarity index 91% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java index a3932487..af78ee77 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java @@ -18,14 +18,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.api.services.chat.v1.HangoutsChat; import io.spine.chatbot.github.repository.build.Build; -import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.thread.ThreadResource; -import static io.spine.chatbot.api.google.chat.HangoutsChatProvider.newHangoutsChat; +import static io.spine.chatbot.google.chat.HangoutsChatProvider.newHangoutsChat; /** * Google Chat API client abstraction. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java index 85ccc25f..0c092dc4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/GoogleChatKey.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java @@ -18,10 +18,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.auth.oauth2.GoogleCredentials; -import io.spine.chatbot.api.google.secret.Secret; +import io.spine.chatbot.google.secret.Secret; import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatProvider.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatProvider.java index 5c9e75eb..de6ff898 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/HangoutsChatProvider.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatProvider.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.HttpTransport; @@ -29,7 +29,7 @@ import java.io.IOException; import java.security.GeneralSecurityException; -import static io.spine.chatbot.api.google.chat.GoogleChatKey.chatServiceAccountKey; +import static io.spine.chatbot.google.chat.GoogleChatKey.chatServiceAccountKey; import static io.spine.util.Exceptions.newIllegalStateException; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java similarity index 91% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java index 7c91e66e..d242bf94 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java @@ -22,11 +22,11 @@ * This package contains Google Chat API facade. * *

    The usage of the Chat API itself it not straightforward. That's why it is recommended to - * use the {@link io.spine.chatbot.api.google.chat.GoogleChatClient facade} instead. + * use the {@link io.spine.chatbot.google.chat.GoogleChatClient facade} instead. */ @CheckReturnValue @ParametersAreNonnullByDefault -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/secret/Secret.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/secret/Secret.java index 983aec96..e7b0dda1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/Secret.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/secret/Secret.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.secret; +package io.spine.chatbot.google.secret; import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; import com.google.cloud.secretmanager.v1.SecretVersionName; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/secret/package-info.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/secret/package-info.java index 489f9809..92224ac0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/google/secret/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/secret/package-info.java @@ -23,7 +23,7 @@ */ @CheckReturnValue @ParametersAreNonnullByDefault -package io.spine.chatbot.api.google.secret; +package io.spine.chatbot.google.secret; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index b8a0ea1e..4ac69152 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.TravisClient; +import io.spine.chatbot.travis.TravisClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index cb923c49..dc6364c4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -23,9 +23,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; -import io.spine.chatbot.api.travis.BuildsQuery; import io.spine.chatbot.api.travis.RepoBranchBuildResponse; -import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; @@ -37,6 +35,8 @@ import io.spine.chatbot.github.repository.build.event.BuildSucceededAgain; import io.spine.chatbot.github.repository.build.rejection.NoBuildsFound; import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.travis.BuildsQuery; +import io.spine.chatbot.travis.TravisClient; import io.spine.logging.Logging; import io.spine.net.Urls; import io.spine.server.command.Assign; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java index c623618a..2d658b4a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildRepository.java @@ -20,9 +20,9 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.RepositoryBuild; +import io.spine.chatbot.travis.TravisClient; import io.spine.server.procman.ProcessManagerRepository; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 76cc5f25..0a902119 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -24,9 +24,7 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; -import io.spine.chatbot.api.travis.ReposQuery; import io.spine.chatbot.api.travis.Repository; -import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.command.RegisterOrganization; @@ -35,6 +33,8 @@ import io.spine.chatbot.github.repository.command.RegisterRepository; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.travis.ReposQuery; +import io.spine.chatbot.travis.TravisClient; import io.spine.core.External; import io.spine.logging.Logging; import io.spine.net.Urls; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java index ddbc8dcc..55f3f256 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java @@ -21,10 +21,10 @@ package io.spine.chatbot.server.github; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.travis.TravisClient; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.travis.TravisClient; import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.route.EventRouting; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index 43604f0e..e956ac38 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.google.chat; -import io.spine.chatbot.api.google.chat.GoogleChatClient; +import io.spine.chatbot.google.chat.GoogleChatClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index ce285ecc..df024937 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -21,11 +21,11 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.concurrent.LazyInit; -import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; +import io.spine.chatbot.google.chat.GoogleChatClient; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.event.MessageCreated; import io.spine.chatbot.google.chat.event.ThreadCreated; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 1c095695..93d3f7f1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -21,9 +21,9 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.google.chat.GoogleChatClient; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; +import io.spine.chatbot.google.chat.GoogleChatClient; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.thread.ThreadChat; import io.spine.chatbot.server.github.RepositoryAwareEvent; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java index af68e3eb..c4604a61 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java @@ -18,8 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; +import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.github.Slug; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java index 5d77daee..a8ef0599 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; import com.google.protobuf.Message; import io.spine.json.Json; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java index a57cbbf6..acd596e6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java index 712e8bd3..1f542e54 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/ReposQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java @@ -18,8 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; +import io.spine.chatbot.api.travis.RepositoriesResponse; import io.spine.chatbot.github.Slug; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Token.java similarity index 94% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/Token.java index e0b17d42..236b0df8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Token.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Token.java @@ -18,9 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; -import io.spine.chatbot.api.google.secret.Secret; +import io.spine.chatbot.google.secret.Secret; import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java index 2607ff36..63d9fa68 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; import java.io.IOException; import java.net.URI; @@ -26,7 +26,7 @@ import java.net.http.HttpRequest; import static com.google.api.client.util.Preconditions.checkNotNull; -import static io.spine.chatbot.api.travis.JsonProtoBodyHandler.jsonBodyHandler; +import static io.spine.chatbot.travis.JsonProtoBodyHandler.jsonBodyHandler; import static java.lang.String.format; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java similarity index 94% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java index a74ff84f..7043996d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java @@ -18,9 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; -import static io.spine.chatbot.api.travis.Token.privateToken; +import static io.spine.chatbot.travis.Token.privateToken; /** * A Travis CI API client. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisResponse.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisResponse.java index 276c549e..e4a1e665 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/TravisResponse.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisResponse.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; import com.google.protobuf.Message; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/package-info.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java rename to google-chat-bot/src/main/java/io/spine/chatbot/travis/package-info.java index 22539042..b6a0bb63 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/api/travis/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/package-info.java @@ -28,7 +28,7 @@ */ @CheckReturnValue @ParametersAreNonnullByDefault -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastAwareClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/FailFastAwareClient.java similarity index 99% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastAwareClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/FailFastAwareClient.java index 2ab9c4b7..dfc80d06 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/FailFastAwareClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/FailFastAwareClient.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api; +package io.spine.chatbot; import io.spine.logging.Logging; import org.checkerframework.checker.nullness.qual.NonNull; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 0c4a13bc..bb7f0341 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -27,10 +27,10 @@ import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; import io.micronaut.test.annotation.MicronautTest; -import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; -import io.spine.chatbot.api.travis.InMemoryTravisClient; +import io.spine.chatbot.google.chat.InMemoryGoogleChatClient; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; +import io.spine.chatbot.travis.InMemoryTravisClient; import io.spine.json.Json; import io.spine.pubsub.PubsubPushRequest; import org.junit.jupiter.api.BeforeAll; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/BuildStateUpdatesTest.java similarity index 96% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/google/chat/BuildStateUpdatesTest.java index 78fd1e9b..259621ba 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/BuildStateUpdatesTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/BuildStateUpdatesTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/ChatWidgetsTest.java similarity index 96% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/google/chat/ChatWidgetsTest.java index 75e4c633..4dcd900c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/ChatWidgetsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/ChatWidgetsTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java similarity index 95% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java index d031f9a1..47f68b6e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java @@ -18,11 +18,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.google.chat; +package io.spine.chatbot.google.chat; -import io.spine.chatbot.api.FailFastAwareClient; +import io.spine.chatbot.FailFastAwareClient; import io.spine.chatbot.github.repository.build.Build; -import io.spine.chatbot.google.chat.BuildStateUpdate; import io.spine.chatbot.google.chat.thread.ThreadResource; import java.util.Map; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java index 2e919a4c..532343b1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.github; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.travis.InMemoryTravisClient; +import io.spine.chatbot.travis.InMemoryTravisClient; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.AfterEach; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java index b1c7141b..ba57aab4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.InMemoryTravisClient; +import io.spine.chatbot.travis.InMemoryTravisClient; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java index 684df73c..bac9d0f6 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java @@ -21,7 +21,7 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; -import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; +import io.spine.chatbot.google.chat.InMemoryGoogleChatClient; import io.spine.server.BoundedContextBuilder; import io.spine.testing.server.blackbox.ContextAwareTest; import org.junit.jupiter.api.AfterEach; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java index 47011754..837e3a6b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.google.chat; -import io.spine.chatbot.api.google.chat.InMemoryGoogleChatClient; +import io.spine.chatbot.google.chat.InMemoryGoogleChatClient; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java similarity index 94% rename from google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java index 3310e3bd..9e6684fa 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/api/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java @@ -18,9 +18,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.api.travis; +package io.spine.chatbot.travis; -import io.spine.chatbot.api.FailFastAwareClient; +import io.spine.chatbot.FailFastAwareClient; +import io.spine.chatbot.api.travis.RepoBranchBuildResponse; +import io.spine.chatbot.api.travis.RepositoriesResponse; import io.spine.chatbot.github.Slug; import java.util.Map; From 998a715a80fc471ff108872303df7e1dd9045659 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 13:35:05 +0300 Subject: [PATCH 424/492] Fix docs --- .../spine/chatbot/google/chat/InMemoryGoogleChatClient.java | 2 +- .../java/io/spine/chatbot/travis/InMemoryTravisClient.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java index 47f68b6e..9c1b0b37 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java @@ -41,7 +41,7 @@ private InMemoryGoogleChatClient(boolean failFast) { } /** - * Creates a {@link #failFast} in-memory Google Chat client. + * Creates a {@link #FailFastAwareClient#failFast failFast} in-memory Google Chat client. */ public static InMemoryGoogleChatClient strictClient() { return new InMemoryGoogleChatClient(true); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java index 9e6684fa..0e1d90b4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java @@ -21,8 +21,6 @@ package io.spine.chatbot.travis; import io.spine.chatbot.FailFastAwareClient; -import io.spine.chatbot.api.travis.RepoBranchBuildResponse; -import io.spine.chatbot.api.travis.RepositoriesResponse; import io.spine.chatbot.github.Slug; import java.util.Map; @@ -43,7 +41,7 @@ private InMemoryTravisClient(boolean failFast) { } /** - * Creates a {@link #failFast} in-memory Travis CI client. + * Creates a {@link #FailFastAwareClient#failFast failFast} in-memory Travis CI client. */ public static InMemoryTravisClient strictClient() { return new InMemoryTravisClient(true); From 16bed439e94ed048115fddfcfdf6f6f963454f4c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 13:37:50 +0300 Subject: [PATCH 425/492] Drop `api` package from `travis.proto` declaration. --- .../server/github/RepoBuildProcess.java | 4 +-- .../server/github/RepositoryAwareEvent.java | 5 --- .../server/github/SpineOrgInitProcess.java | 2 +- .../io/spine/chatbot/travis/BuildsQuery.java | 1 - .../java/io/spine/chatbot/travis/Query.java | 2 +- .../io/spine/chatbot/travis/ReposQuery.java | 1 - .../java/io/spine/chatbot/travis/Travis.java | 2 +- .../proto/spine/chatbot/travis/travis.proto | 2 +- .../server/github/RepoBuildProcessTest.java | 34 +++++++++---------- .../github/SpineOrgInitProcessTest.java | 4 +-- 10 files changed, 25 insertions(+), 32 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index dc6364c4..2e6e913d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -23,7 +23,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; -import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; @@ -36,6 +35,7 @@ import io.spine.chatbot.github.repository.build.rejection.NoBuildsFound; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.travis.BuildsQuery; +import io.spine.chatbot.travis.RepoBranchBuildResponse; import io.spine.chatbot.travis.TravisClient; import io.spine.logging.Logging; import io.spine.net.Urls; @@ -181,7 +181,7 @@ static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { .vBuild(); } - private static Commit from(io.spine.chatbot.api.travis.Commit commit) { + private static Commit from(io.spine.chatbot.travis.Commit commit) { return Commit .newBuilder() .setSha(commit.getSha()) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java index 82e7c32f..d4bcfd5e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java @@ -23,11 +23,6 @@ import com.google.errorprone.annotations.Immutable; import io.spine.annotation.GeneratedMixin; import io.spine.base.EventMessage; -import io.spine.chatbot.github.RepositoryId; - -import java.util.Set; - -import static io.spine.server.route.EventRoute.withId; /** * A repository-aware event message. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 0a902119..014e6a3c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; -import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.command.RegisterOrganization; @@ -34,6 +33,7 @@ import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; import io.spine.chatbot.travis.ReposQuery; +import io.spine.chatbot.travis.Repository; import io.spine.chatbot.travis.TravisClient; import io.spine.core.External; import io.spine.logging.Logging; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java index c4604a61..25ef3842 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java @@ -20,7 +20,6 @@ package io.spine.chatbot.travis; -import io.spine.chatbot.api.travis.RepoBranchBuildResponse; import io.spine.chatbot.github.Slug; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java index acd596e6..bdf9e285 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java @@ -31,7 +31,7 @@ * @param * type of the expected query execution response */ -public abstract class Query { +abstract class Query { private final Class responseType; private final String request; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java index 1f542e54..8cf5513d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/ReposQuery.java @@ -20,7 +20,6 @@ package io.spine.chatbot.travis; -import io.spine.chatbot.api.travis.RepositoriesResponse; import io.spine.chatbot.github.Slug; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java index 63d9fa68..b6af5409 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java @@ -37,7 +37,7 @@ final class Travis implements TravisClient { private static final HttpClient CLIENT = HttpClient.newHttpClient(); - private static final String BASE_URL = "https://api.travis-ci.com"; + private static final String BASE_URL = "https://travis-ci.com"; private static final String API_HEADER = "Travis-API-Version"; private static final String API_VERSION = "3"; private static final String AUTH_HEADER = "Authorization"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto index 64d52f2e..dc4af61e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/travis/travis.proto @@ -32,7 +32,7 @@ package spine.chatbot.travis; import "spine/options.proto"; option (type_url_prefix) = "type.spine.io.chatbot"; -option java_package = "io.spine.chatbot.api.travis"; +option java_package = "io.spine.chatbot.travis"; option java_outer_classname = "TravisCiApiProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 3d607248..f73e1d96 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -20,10 +20,6 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.Author; -import io.spine.chatbot.api.travis.Commit; -import io.spine.chatbot.api.travis.RepoBranchBuildResponse; -import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.repository.build.Build; @@ -35,6 +31,10 @@ import io.spine.chatbot.github.repository.build.event.BuildSucceededAgain; import io.spine.chatbot.github.repository.build.rejection.RepositoryBuildRejections; import io.spine.chatbot.google.chat.SpaceId; +import io.spine.chatbot.travis.Author; +import io.spine.chatbot.travis.Commit; +import io.spine.chatbot.travis.RepoBranchBuildResponse; +import io.spine.chatbot.travis.Repository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -77,7 +77,7 @@ void throwNoBuildsFoundRejection() { @DisplayName("handle build failure") final class FailedBuild { - private final io.spine.chatbot.api.travis.Build build = failedBuild(); + private final io.spine.chatbot.travis.Build build = failedBuild(); private final RepoBranchBuildResponse branchBuild = branchBuildOf(build); private final Build buildState = buildFrom(branchBuild, chatSpace); @@ -127,12 +127,12 @@ void settingState() { @DisplayName("handle build recovery") final class RecoveredBuild { - private final io.spine.chatbot.api.travis.Build previousBuild = failedBuild(); + private final io.spine.chatbot.travis.Build previousBuild = failedBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); private final Build previousBuildState = buildFrom(previousBranchBuild, chatSpace); - private final io.spine.chatbot.api.travis.Build newBuild = passingBuild(); + private final io.spine.chatbot.travis.Build newBuild = passingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); private final Build newBuildState = buildFrom(newBranchBuild, chatSpace); @@ -191,14 +191,14 @@ void settingState() { @DisplayName("handle stable builds") final class StableBuild { - private final io.spine.chatbot.api.travis.Build initialFailedBuild = failedBuild(); + private final io.spine.chatbot.travis.Build initialFailedBuild = failedBuild(); - private final io.spine.chatbot.api.travis.Build previousBuild = passingBuild(); + private final io.spine.chatbot.travis.Build previousBuild = passingBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); private final Build previousBuildState = buildFrom(previousBranchBuild, chatSpace); - private final io.spine.chatbot.api.travis.Build newBuild = nextPassingBuild(); + private final io.spine.chatbot.travis.Build newBuild = nextPassingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); private final Build newBuildState = buildFrom(newBranchBuild, chatSpace); @@ -261,7 +261,7 @@ void settingState() { } } - private static RepoBranchBuildResponse branchBuildOf(io.spine.chatbot.api.travis.Build build) { + private static RepoBranchBuildResponse branchBuildOf(io.spine.chatbot.travis.Build build) { return RepoBranchBuildResponse .newBuilder() .setLastBuild(build) @@ -271,8 +271,8 @@ private static RepoBranchBuildResponse branchBuildOf(io.spine.chatbot.api.travis .buildPartial(); } - private static io.spine.chatbot.api.travis.Build passingBuild() { - return io.spine.chatbot.api.travis.Build + private static io.spine.chatbot.travis.Build passingBuild() { + return io.spine.chatbot.travis.Build .newBuilder() .setId(123153L) .setNumber("42") @@ -283,8 +283,8 @@ private static io.spine.chatbot.api.travis.Build passingBuild() { .buildPartial(); } - private static io.spine.chatbot.api.travis.Build nextPassingBuild() { - return io.spine.chatbot.api.travis.Build + private static io.spine.chatbot.travis.Build nextPassingBuild() { + return io.spine.chatbot.travis.Build .newBuilder() .setId(123154L) .setNumber("43") @@ -295,8 +295,8 @@ private static io.spine.chatbot.api.travis.Build nextPassingBuild() { .buildPartial(); } - private static io.spine.chatbot.api.travis.Build failedBuild() { - return io.spine.chatbot.api.travis.Build + private static io.spine.chatbot.travis.Build failedBuild() { + return io.spine.chatbot.travis.Build .newBuilder() .setId(123152L) .setNumber("41") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index a7af9d7b..5b783eb1 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -20,12 +20,12 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.api.travis.RepositoriesResponse; -import io.spine.chatbot.api.travis.Repository; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.SpaceHeader; import io.spine.chatbot.google.chat.SpaceId; import io.spine.chatbot.google.chat.event.SpaceRegistered; +import io.spine.chatbot.travis.RepositoriesResponse; +import io.spine.chatbot.travis.Repository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; From c1865f82ce7323521a228066786d53164f487640 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 14:50:44 +0300 Subject: [PATCH 426/492] Use proper type name in the exception. --- .../src/main/java/io/spine/chatbot/BeanFactory.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 1f99824b..190a9cff 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -34,6 +34,8 @@ import javax.inject.Singleton; import java.io.IOException; +import static io.spine.util.Exceptions.newIllegalArgumentException; + /** * Creates Micronaut context bean definitions. */ @@ -87,7 +89,9 @@ public PubsubPushRequest deserialize(JsonParser parser, DeserializationContext c .vBuild(); return result; } catch (IOException e) { - throw new RuntimeException("Unable to deserialize PubsubPushNotification json.", e); + throw newIllegalArgumentException( + e, "Unable to deserialize `PubsubPushRequest` json." + ); } } } From 56617f3191878bb2bc2f93e4baa2b07703be0e48 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 15:44:06 +0300 Subject: [PATCH 427/492] Drop args usage. --- .../src/main/java/io/spine/chatbot/Application.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 7ca3e02c..5a206e0e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -37,7 +37,7 @@ /** * The entry point to the Spine ChatBot application. * - *

    The application itself exposes a number of REST endpoints accessible for the clients such as: + *

    The application exposes a number of REST endpoints accessible for the clients such as: * *

      *
    • {@code /chat/incoming/event} — handles incoming events from the Google Chat space. @@ -73,16 +73,14 @@ private Application() { */ public static void main(String[] args) { var application = new Application(); - application.start(args); + application.start(); } /** - * Starts the application. - * - *

      Performs bounded contexts initialization, starts GRPC {@link Server} and runs + * Performs bounded contexts initialization, starts GRPC {@link Server} and runs * the {@link Micronaut}. */ - private void start(String[] args) { + private void start() { _config().log("Initializing server environment."); ChatBotServerEnvironment.init(); _config().log("Setting up bounded contexts."); @@ -95,7 +93,7 @@ private void start(String[] args) { _config().log("Starting GRPC server."); var server = startServer(gitHubContext, googleChatContext); _config().log("Starting Micronaut application."); - var applicationContext = Micronaut.run(Application.class, args); + var applicationContext = Micronaut.run(Application.class); applicationContext.registerSingleton(new ShutdownHook(server)); } From 853c30af4688b7c59b0a28adad173e6e4157a66f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 16:33:31 +0300 Subject: [PATCH 428/492] Add ContextBuilderAware common interface. Expose `newInstance` methods for creation of the new context instances --- .../chatbot/server/ContextBuilderAware.java | 35 +++++++++++++++++++ .../chatbot/server/github/GitHubContext.java | 11 +++++- .../server/google/chat/GoogleChatContext.java | 11 +++++- .../io/spine/chatbot/server/package-info.java | 33 +++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/ContextBuilderAware.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/ContextBuilderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/ContextBuilderAware.java new file mode 100644 index 00000000..d7737bca --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/ContextBuilderAware.java @@ -0,0 +1,35 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server; + +import io.spine.server.BoundedContextBuilder; + +/** + * Common interface for {@link io.spine.server.BoundedContext BoundedContext} providers + * aware of the {@link BoundedContextBuilder}. + */ +public interface ContextBuilderAware { + + /** + * Returns the context builder associated with context. + */ + BoundedContextBuilder builder(); +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 4ac69152..93127a8c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.github; +import io.spine.chatbot.server.ContextBuilderAware; import io.spine.chatbot.travis.TravisClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -29,7 +30,7 @@ /** * Provides {@link BoundedContextBuilder} for the GitHub context. */ -public final class GitHubContext { +public final class GitHubContext implements ContextBuilderAware { /** * The name of the GitHub Context. @@ -45,6 +46,7 @@ private GitHubContext(TravisClient client) { /** * Returns the context builder associated with the GitHub context. */ + @Override public BoundedContextBuilder builder() { return this.builder; } @@ -66,6 +68,13 @@ public static Builder newBuilder() { return new Builder(); } + /** + * Creates a new GitHub context. + */ + public static GitHubContext newInstance() { + return newBuilder().build(); + } + /** * A Builder for configuring GitHub context. */ diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index e956ac38..bd4e67d1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.google.chat; import io.spine.chatbot.google.chat.GoogleChatClient; +import io.spine.chatbot.server.ContextBuilderAware; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -29,7 +30,7 @@ /** * Provides {@link BoundedContextBuilder} for the Google Chat context. */ -public final class GoogleChatContext { +public final class GoogleChatContext implements ContextBuilderAware { /** The name of the Google Chat Context. **/ static final String GOOGLE_CHAT_CONTEXT_NAME = "GoogleChat"; @@ -43,6 +44,7 @@ private GoogleChatContext(GoogleChatClient client) { /** * Returns the context builder associated with the Google Chat context. */ + @Override public BoundedContextBuilder builder() { return this.builder; } @@ -67,6 +69,13 @@ public static Builder newBuilder() { return new Builder(); } + /** + * Creates a new Google Chat context. + */ + public static GoogleChatContext newInstance() { + return newBuilder().build(); + } + /** * A Builder for configuring Google Chat context. */ diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java new file mode 100644 index 00000000..e7c73d0d --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java @@ -0,0 +1,33 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains the ChatBot server. + */ +@BoundedContext(GitHubContext.GIT_HUB_CONTEXT_NAME) +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.server; + +import com.google.errorprone.annotations.CheckReturnValue; +import io.spine.chatbot.server.github.GitHubContext; +import io.spine.core.BoundedContext; + +import javax.annotation.ParametersAreNonnullByDefault; From 35ff64d19466ceaac3fd14b1ef49c417203ee5dc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:09:48 +0300 Subject: [PATCH 429/492] Extract dedicated Server abstraction --- .../java/io/spine/chatbot/Application.java | 73 +--------- .../spine/chatbot/RepositoriesController.java | 5 +- .../java/io/spine/chatbot/package-info.java | 3 +- .../java/io/spine/chatbot/server/Server.java | 127 ++++++++++++++++++ .../ServerEnvironment.java} | 13 +- .../io/spine/chatbot/server/package-info.java | 3 - .../chatbot/IncomingEventsControllerTest.java | 6 +- 7 files changed, 144 insertions(+), 86 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java rename google-chat-bot/src/main/java/io/spine/chatbot/{ChatBotServerEnvironment.java => server/ServerEnvironment.java} (90%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 5a206e0e..3235b67d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -20,19 +20,11 @@ package io.spine.chatbot; -import com.google.common.annotations.VisibleForTesting; -import io.micronaut.context.event.ApplicationEventListener; -import io.micronaut.context.event.ShutdownEvent; import io.micronaut.runtime.Micronaut; +import io.spine.chatbot.server.Server; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.logging.Logging; -import io.spine.server.Server; - -import java.io.IOException; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.util.Exceptions.newIllegalStateException; /** * The entry point to the Spine ChatBot application. @@ -56,9 +48,6 @@ public final class Application implements Logging { ); } - /** Name of the GRPC {@link Server}. **/ - static final String SERVER_NAME = "ChatBotServer"; - /** * Prevents direct instantiation. */ @@ -77,64 +66,12 @@ public static void main(String[] args) { } /** - * Performs bounded contexts initialization, starts GRPC {@link Server} and runs - * the {@link Micronaut}. + * Starts {@link Server} and runs the {@link Micronaut}. */ private void start() { - _config().log("Initializing server environment."); - ChatBotServerEnvironment.init(); - _config().log("Setting up bounded contexts."); - var gitHubContext = GitHubContext - .newBuilder() - .build(); - var googleChatContext = GoogleChatContext - .newBuilder() - .build(); - _config().log("Starting GRPC server."); - var server = startServer(gitHubContext, googleChatContext); + Server.withContexts(GitHubContext.newInstance(), GoogleChatContext.newInstance()) + .start(); _config().log("Starting Micronaut application."); - var applicationContext = Micronaut.run(Application.class); - applicationContext.registerSingleton(new ShutdownHook(server)); - } - - /** - * Starts in-process GRPC server. - */ - @VisibleForTesting - static Server startServer(GitHubContext gitHubContext, GoogleChatContext googleChatContext) { - Server server = Server - .inProcess(SERVER_NAME) - .add(gitHubContext.builder()) - .add(googleChatContext.builder()) - .build(); - try { - server.start(); - } catch (IOException e) { - throw newIllegalStateException( - e, "Unable to start Spine GRPC server `%s`.", SERVER_NAME - ); - } - return server; - } - - /** - * Gracefully stops the {@link #server}. - */ - private static final class ShutdownHook - implements ApplicationEventListener, Logging { - - private final Server server; - - private ShutdownHook(Server server) { - this.server = checkNotNull(server); - } - - @Override - public void onApplicationEvent(ShutdownEvent event) { - _info().log("Shutting down the application."); - if (server != null) { - server.shutdownAndWait(); - } - } + Micronaut.run(Application.class); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 2d7f39e1..b1bb5d16 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -26,10 +26,9 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; +import io.spine.chatbot.server.Server; import io.spine.logging.Logging; -import static io.spine.chatbot.Application.SERVER_NAME; - /** * A REST controller handling Repository commands. */ @@ -42,7 +41,7 @@ final class RepositoriesController implements Logging { @Post("/builds/check") String checkBuildStatuses() { _debug().log("Checking repositories build statuses."); - try (var client = Client.inProcessClient(SERVER_NAME)) { + try (var client = Client.inProcessClient(Server.name())) { var organizations = client.listOrganizations(); for (var organization : organizations) { var repos = client.listOrgRepos(organization.getId()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java index f5a9cb05..d1c87156 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java @@ -19,8 +19,7 @@ */ /** - * This contains package the application {@link io.spine.chatbot.Application entry point} - * and the {@link io.spine.chatbot.ChatBotServerEnvironment environment} configurations. + * This contains package the application {@link io.spine.chatbot.Application entry point}. */ @CheckReturnValue @ParametersAreNonnullByDefault diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java new file mode 100644 index 00000000..f1f7f252 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java @@ -0,0 +1,127 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server; + +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.concurrent.LazyInit; +import io.spine.logging.Logging; + +import java.io.IOException; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Exceptions.newIllegalStateException; + +/** + * A ChatBot application's Spine server. + * + *

      Abstracts working with Spine's {@link io.spine.server.Server server}. + */ +public final class Server implements Logging { + + /** Name of the GRPC {@link io.spine.server.Server}. **/ + private static final String SERVER_NAME = "ChatBotServer"; + + private final ImmutableSet contexts; + + @LazyInit + private io.spine.server.Server grpcServer; + + private Server(ImmutableSet contexts) { + this.contexts = contexts; + } + + /** + * Returns the name of the server. + */ + public static String name() { + return SERVER_NAME; + } + + /** + * Starts the server. + * + *

      Performs {@linkplain #init() initialization} of the server if it was not + * previously initialized. + */ + public void start() { + if (grpcServer == null) { + init(); + } + try { + _config().log("Starting GRPC server."); + grpcServer.start(); + Runtime.getRuntime() + .addShutdownHook(ShutdownHook.newInstance(grpcServer)); + } catch (IOException e) { + throw newIllegalStateException( + e, "Unable to start Spine GRPC server `%s`.", SERVER_NAME + ); + } + } + + /** + * Initializes the server and its {@link ServerEnvironment environment}. + */ + public void init() { + _config().log("Initializing server environment."); + ServerEnvironment.init(); + _config().log("Bootstrapping server."); + io.spine.server.Server.Builder serverBuilder = io.spine.server.Server.inProcess( + SERVER_NAME); + for (ContextBuilderAware contextAware : contexts) { + serverBuilder.add(contextAware.builder()); + } + grpcServer = serverBuilder.build(); + } + + /** + * Creates a new in-process GRPC server with the supplied {@code contexts}. + */ + public static Server withContexts(ContextBuilderAware... contexts) { + checkNotNull(contexts); + checkArgument(contexts.length > 0, "At least a single Bounded Context is required."); + return new Server(ImmutableSet.copyOf(contexts)); + } + + /** + * Gracefully stops the {@link #server}. + */ + private static final class ShutdownHook implements Runnable, Logging { + + private final io.spine.server.Server server; + + private ShutdownHook(io.spine.server.Server server) { + this.server = server; + } + + private static Thread newInstance(io.spine.server.Server server) { + checkNotNull(server); + return new Thread(new ShutdownHook(server)); + } + + @Override + public void run() { + _info().log("Shutting down the GRPC server."); + server.shutdownAndWait(); + } + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java similarity index 90% rename from google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java index d72f1a93..9ef2c4aa 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/ChatBotServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java @@ -18,14 +18,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot; +package io.spine.chatbot.server; import com.google.cloud.datastore.DatastoreOptions; import io.spine.base.Environment; import io.spine.base.Production; import io.spine.base.Tests; import io.spine.chatbot.delivery.LocalDelivery; -import io.spine.server.ServerEnvironment; import io.spine.server.storage.StorageFactory; import io.spine.server.storage.datastore.DatastoreStorageFactory; import io.spine.server.storage.memory.InMemoryStorageFactory; @@ -34,7 +33,7 @@ /** * ChatBot server environment definition. * - *

      Initializes the {@link ServerEnvironment}. + *

      Initializes the {@link io.spine.server.ServerEnvironment}. * *

      Configures the {@link StorageFactory} based on * the current {@link Environment} — Datastore-based for Production and in-memory-based for tests. @@ -42,22 +41,22 @@ *

      Configures the inbox delivery through the Datastore work registry while * in Production environment, otherwise uses local synchronous delivery. */ -final class ChatBotServerEnvironment { +final class ServerEnvironment { /** * Prevents instantiation of this utility class. */ - private ChatBotServerEnvironment() { + private ServerEnvironment() { } /** - * Initializes {@link ServerEnvironment} for ChatBot. + * Initializes {@link io.spine.server.ServerEnvironment ServerEnvironment} for ChatBot. */ static void init() { //TODO:2020-06-21:yuri-sergiichuk: switch to io.spine.chatbot.delivery.DistributedDelivery // for Production environment after implementing the delivery strategy. // see https://github.com/SpineEventEngine/chat-bot/issues/5. - ServerEnvironment + io.spine.server.ServerEnvironment .instance() .use(InMemoryTransportFactory.newInstance(), Production.class) .use(LocalDelivery.instance, Production.class) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java index e7c73d0d..bf59b25b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/package-info.java @@ -21,13 +21,10 @@ /** * This package contains the ChatBot server. */ -@BoundedContext(GitHubContext.GIT_HUB_CONTEXT_NAME) @CheckReturnValue @ParametersAreNonnullByDefault package io.spine.chatbot.server; import com.google.errorprone.annotations.CheckReturnValue; -import io.spine.chatbot.server.github.GitHubContext; -import io.spine.core.BoundedContext; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index bb7f0341..59ca4afe 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -28,6 +28,7 @@ import io.micronaut.http.client.annotation.Client; import io.micronaut.test.annotation.MicronautTest; import io.spine.chatbot.google.chat.InMemoryGoogleChatClient; +import io.spine.chatbot.server.Server; import io.spine.chatbot.server.github.GitHubContext; import io.spine.chatbot.server.google.chat.GoogleChatContext; import io.spine.chatbot.travis.InMemoryTravisClient; @@ -42,7 +43,6 @@ import java.nio.charset.StandardCharsets; import static io.micronaut.http.HttpRequest.POST; -import static io.spine.chatbot.Application.startServer; import static io.spine.util.Exceptions.newIllegalStateException; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -54,7 +54,6 @@ final class IncomingEventsControllerTest { @Client("/") private HttpClient client; - @SuppressWarnings("ResultOfMethodCallIgnored") // we're not interested in GRPC server here @BeforeAll static void setupServer() { var chatContext = GoogleChatContext @@ -65,7 +64,8 @@ static void setupServer() { .newBuilder() .setTravis(InMemoryTravisClient.lenientClient()) .build(); - startServer(gitHubContext, chatContext); + Server.withContexts(chatContext, gitHubContext) + .start(); } @Test From a035274e0cbfda48ca5bd39b7837bd057ae4f2c0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:13:20 +0300 Subject: [PATCH 430/492] Extract flogger config into a function --- .../main/java/io/spine/chatbot/Application.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index 3235b67d..e703f4a0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -42,10 +42,7 @@ public final class Application implements Logging { static { - System.setProperty( - "flogger.backend_factory", - "com.google.common.flogger.backend.log4j2.Log4j2BackendFactory#getInstance" - ); + useLog4j2FloggerBackend(); } /** @@ -74,4 +71,14 @@ private void start() { _config().log("Starting Micronaut application."); Micronaut.run(Application.class); } + + /** + * Configures Log4j2 as the Flogger backend. + */ + private static void useLog4j2FloggerBackend() { + System.setProperty( + "flogger.backend_factory", + "com.google.common.flogger.backend.log4j2.Log4j2BackendFactory#getInstance" + ); + } } From 01b1bdf4804a2fe6e4497866521678bdb272c5fe Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:15:54 +0300 Subject: [PATCH 431/492] Improve docs --- .../java/io/spine/chatbot/server/ServerEnvironment.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java index 9ef2c4aa..050118dc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java @@ -31,12 +31,10 @@ import io.spine.server.transport.memory.InMemoryTransportFactory; /** - * ChatBot server environment definition. + * Initializes the {@link io.spine.server.ServerEnvironment}. * - *

      Initializes the {@link io.spine.server.ServerEnvironment}. - * - *

      Configures the {@link StorageFactory} based on - * the current {@link Environment} — Datastore-based for Production and in-memory-based for tests. + *

      Configures the {@link StorageFactory} depending on the current {@link Environment}. + * Uses the Datastore storage factory for the production mode and in-memory storage for tests. * *

      Configures the inbox delivery through the Datastore work registry while * in Production environment, otherwise uses local synchronous delivery. From 3749db737254032a3db8027e01a8a7e438c815b6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:28:44 +0300 Subject: [PATCH 432/492] Rename third-party context --- .../spine/chatbot/IncomingEventsController.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index ae5307d5..eddda0cc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -42,9 +42,9 @@ @Controller("/chat") final class IncomingEventsController implements Logging { - private static final String INCOMING_EVENTS_CONTEXT_NAME = "IncomingChatEvents"; - private static final ThirdPartyContext INCOMING_EVENTS = - ThirdPartyContext.singleTenant(INCOMING_EVENTS_CONTEXT_NAME); + private static final String GOOGLE_CHAT_SERVER_CONTEXT_NAME = "GoogleChatServer"; + private static final ThirdPartyContext GOOGLE_CHAT_SERVER = + ThirdPartyContext.singleTenant(GOOGLE_CHAT_SERVER_CONTEXT_NAME); /** * Processes an incoming Google Chat event. @@ -63,7 +63,7 @@ String on(@Body PubsubPushRequest pushNotification) { .newBuilder() .setEvent(chatEvent) .vBuild(); - INCOMING_EVENTS.emittedEvent(chatEventReceived, actor); + GOOGLE_CHAT_SERVER.emittedEvent(chatEventReceived, actor); return "OK"; } @@ -75,16 +75,17 @@ private static UserId eventActor(User user) { } /** - * Cleans up resources of the {@link #INCOMING_EVENTS context}. + * Cleans up resources of the {@link #GOOGLE_CHAT_SERVER context}. */ @EventListener void on(ShutdownEvent event) { - _info().log("Closing `%s` third-party context.", INCOMING_EVENTS_CONTEXT_NAME); + _info().log("Closing `%s` third-party context.", GOOGLE_CHAT_SERVER_CONTEXT_NAME); try { - INCOMING_EVENTS.close(); + GOOGLE_CHAT_SERVER.close(); } catch (Exception e) { _error().withCause(e) - .log("Unable to gracefully close `%s` context.", INCOMING_EVENTS_CONTEXT_NAME); + .log("Unable to gracefully close `%s` context.", + GOOGLE_CHAT_SERVER_CONTEXT_NAME); } } } From 749f6b894e9cb2c38a959b8e7f4f8665af48f538 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:32:10 +0300 Subject: [PATCH 433/492] Add missing @MonotonicNonNull annotation --- .../src/main/java/io/spine/chatbot/server/Server.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java index f1f7f252..b084fc4b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.logging.Logging; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import java.io.IOException; @@ -43,7 +44,7 @@ public final class Server implements Logging { private final ImmutableSet contexts; @LazyInit - private io.spine.server.Server grpcServer; + private io.spine.server.@MonotonicNonNull Server grpcServer; private Server(ImmutableSet contexts) { this.contexts = contexts; From 86b3fe57a5fefe04f182ece0800a07823a98b1c3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:35:17 +0300 Subject: [PATCH 434/492] Wire client with server --- .../java/io/spine/chatbot/RepositoriesController.java | 3 +-- .../src/main/java/io/spine/chatbot/client/Client.java | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index b1bb5d16..4760bd70 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -26,7 +26,6 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; -import io.spine.chatbot.server.Server; import io.spine.logging.Logging; /** @@ -41,7 +40,7 @@ final class RepositoriesController implements Logging { @Post("/builds/check") String checkBuildStatuses() { _debug().log("Checking repositories build statuses."); - try (var client = Client.inProcessClient(Server.name())) { + try (var client = Client.newInstance()) { var organizations = client.listOrganizations(); for (var organization : organizations) { var repos = client.listOrgRepos(organization.getId()); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index bb27c968..c31670b6 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -28,6 +28,7 @@ import io.spine.chatbot.github.RepositoryId; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.OrganizationRepositories; +import io.spine.chatbot.server.Server; import io.spine.client.CommandRequest; import io.spine.client.Subscription; @@ -51,12 +52,11 @@ private Client(io.spine.client.Client client) { } /** - * Creates a new in-process client configured for the specified server. + * Creates a new in-process client linked to the {@link Server}. */ - public static Client inProcessClient(String serverName) { - checkNotNull(serverName); + public static Client newInstance() { io.spine.client.Client client = io.spine.client.Client - .inProcess(serverName) + .inProcess(Server.name()) .build(); return new Client(client); } From e62654a03353a9ec3a5c9f416d5d73ff436eb2f2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:39:45 +0300 Subject: [PATCH 435/492] Cleanup docs --- .../chatbot/IncomingEventsController.java | 4 ++-- .../spine/chatbot/RepositoriesController.java | 23 ++++++++----------- .../java/io/spine/chatbot/server/Server.java | 18 +++++++-------- .../server/google/chat/ThreadChatProcess.java | 10 ++++---- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index eddda0cc..c8facb42 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -52,8 +52,8 @@ final class IncomingEventsController implements Logging { *

      Dispatches the event using {@link ThirdPartyContext}. */ @Post(value = "/incoming/event", consumes = APPLICATION_JSON) - String on(@Body PubsubPushRequest pushNotification) { - var message = pushNotification.getMessage(); + String on(@Body PubsubPushRequest pushRequest) { + var message = pushRequest.getMessage(); var chatEventJson = message.getData() .toStringUtf8(); _debug().log("Received a new chat event: %s", chatEventJson); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index 4760bd70..ab02e861 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -42,30 +42,27 @@ String checkBuildStatuses() { _debug().log("Checking repositories build statuses."); try (var client = Client.newInstance()) { var organizations = client.listOrganizations(); - for (var organization : organizations) { - var repos = client.listOrgRepos(organization.getId()); - repos.forEach(repo -> checkBuildStatus(client, repo, organization)); + for (var org : organizations) { + var repos = client.listOrgRepos(org.getId()); + repos.forEach(repo -> checkBuildStatus(client, repo, org)); } return "success"; } } - private void checkBuildStatus(Client client, - RepositoryId repository, - Organization organization) { + private void checkBuildStatus(Client client, RepositoryId repo, Organization org) { _info().log("Sending `%s` command for the repository `%s`.", - CheckRepositoryBuild.class.getSimpleName(), repository.getValue()); - var checkRepositoryBuild = checkRepoBuildCommand(repository, organization); + CheckRepositoryBuild.class.getSimpleName(), repo.getValue()); + var checkRepositoryBuild = checkRepoBuildCommand(repo, org); client.post(checkRepositoryBuild); } - private static CheckRepositoryBuild - checkRepoBuildCommand(RepositoryId repository, Organization organization) { + private static CheckRepositoryBuild checkRepoBuildCommand(RepositoryId repo, Organization org) { return CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setOrganization(organization.getId()) - .setSpace(organization.space()) + .setRepository(repo) + .setOrganization(org.getId()) + .setSpace(org.space()) .vBuild(); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java index b084fc4b..f1fd714a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java @@ -50,6 +50,15 @@ private Server(ImmutableSet contexts) { this.contexts = contexts; } + /** + * Creates a new in-process GRPC server with the supplied {@code contexts}. + */ + public static Server withContexts(ContextBuilderAware... contexts) { + checkNotNull(contexts); + checkArgument(contexts.length > 0, "At least a single Bounded Context is required."); + return new Server(ImmutableSet.copyOf(contexts)); + } + /** * Returns the name of the server. */ @@ -94,15 +103,6 @@ public void init() { grpcServer = serverBuilder.build(); } - /** - * Creates a new in-process GRPC server with the supplied {@code contexts}. - */ - public static Server withContexts(ContextBuilderAware... contexts) { - checkNotNull(contexts); - checkArgument(contexts.length > 0, "At least a single Bounded Context is required."); - return new Server(ImmutableSet.copyOf(contexts)); - } - /** * Gracefully stops the {@link #server}. */ diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index df024937..89f92ba1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -56,9 +56,9 @@ final class ThreadChatProcess extends ProcessManager> on(@External BuildFailed e) { var change = e.getChange(); var build = change.getNewValue(); - var repository = e.getRepository(); - _info().log("A build for the repository `%s` failed.", repository.getValue()); - return processBuildStateUpdate(build, repository); + var repo = e.getRepository(); + _info().log("A build for the repository `%s` failed.", repo.getValue()); + return processBuildStateUpdate(build, repo); } /** @@ -77,7 +77,7 @@ Pair> on(@External BuildRecovered e) { } private Pair> - processBuildStateUpdate(Build build, RepositoryId repository) { + processBuildStateUpdate(Build build, RepositoryId repo) { var sentUpdate = client.sendBuildStateUpdate(build, state().getResource()); var space = sentUpdate.getSpace(); var thread = sentUpdate.getThread(); @@ -90,7 +90,7 @@ Pair> on(@External BuildRecovered e) { if (shouldCreateThread()) { var resource = sentUpdate.getResource(); _debug().log("A new thread `%s` created for the repository `%s`.", - resource.getName(), repository.getValue()); + resource.getName(), repo.getValue()); builder().setResource(resource) .setSpace(space); var threadCreated = ThreadCreated From 6638bfa1118830cff6318aafa011a716abba4b27 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:40:49 +0300 Subject: [PATCH 436/492] Use less important log level --- .../main/java/io/spine/chatbot/RepositoriesController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java index ab02e861..f092ed99 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/RepositoriesController.java @@ -51,8 +51,8 @@ String checkBuildStatuses() { } private void checkBuildStatus(Client client, RepositoryId repo, Organization org) { - _info().log("Sending `%s` command for the repository `%s`.", - CheckRepositoryBuild.class.getSimpleName(), repo.getValue()); + _debug().log("Sending `%s` command for the repository `%s`.", + CheckRepositoryBuild.class.getSimpleName(), repo.getValue()); var checkRepositoryBuild = checkRepoBuildCommand(repo, org); client.post(checkRepositoryBuild); } From b075c6cfb8ec9ee5bc29686107054c7eca52f691 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:43:21 +0300 Subject: [PATCH 437/492] Cleanup docs --- .../chatbot/delivery/DistributedDelivery.java | 4 ++-- .../io/spine/chatbot/delivery/ShardDelivery.java | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java index 133400af..f33df478 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/DistributedDelivery.java @@ -30,11 +30,11 @@ * Delivers messages using Datastore as the underlying storage. * *

      The delivery is based on the {@link DatastoreStorageFactory Datastore} and uses - * {@link DsShardedWorkRegistry} as the {@link ShardedWorkRegistry work registry}. + * {@link DsShardedWorkRegistry} as the {@linkplain ShardedWorkRegistry work registry}. */ final class DistributedDelivery { - /** The number of shards used for the signals delivery. **/ + /** The number of shards used for the signal delivery. **/ private static final int NUMBER_OF_SHARDS = 50; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java index 3f073588..e8548cc0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/delivery/ShardDelivery.java @@ -26,13 +26,14 @@ import io.spine.server.delivery.ShardIndex; import io.spine.server.delivery.ShardedRecord; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Delivers messages from a particular shard. * *

      Wraps the {@link io.spine.server.delivery.Delivery#deliverMessagesFrom(ShardIndex) - * Delivery#deliverMessagesFrom} - * with server environment-specific logging and provides helpers that unifies the usage of the - * delivery. + * Delivery#deliverMessagesFrom} with server environment-specific logging and provides helpers + * that unifies the usage of the delivery. */ final class ShardDelivery implements Logging { @@ -46,13 +47,15 @@ private ShardDelivery(ShardIndex shard) { * Delivers the {@code message}. */ static void deliver(ShardedRecord message) { + checkNotNull(message); deliverFrom(message.shardIndex()); } /** * Delivers messages from the {@code shard}. */ - static void deliverFrom(ShardIndex shard) { + private static void deliverFrom(ShardIndex shard) { + checkNotNull(shard); var delivery = new ShardDelivery(shard); delivery.deliverNow(); } @@ -63,8 +66,8 @@ private void deliverNow() { var nodeId = server.nodeId() .getValue(); var indexValue = shard.getIndex(); - trace.log("Delivering messages from the shard with index `%d`. NodeId=%s.", indexValue, - nodeId); + trace.log("Delivering messages from the shard with index `%d`. NodeId=%s.", + indexValue, nodeId); var stats = server.delivery() .deliverMessagesFrom(shard); if (stats.isPresent()) { From 3d1bec58cc8598ef3dbb11ccb8355c95d88c9fce Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:44:18 +0300 Subject: [PATCH 438/492] Improve wording --- .../java/io/spine/chatbot/google/chat/GoogleChatClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java index af78ee77..1a4b9664 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java @@ -27,7 +27,7 @@ import static io.spine.chatbot.google.chat.HangoutsChatProvider.newHangoutsChat; /** - * Google Chat API client abstraction. + * A client to the Google Chat server. * *

      Abstracts out usage of the chat API by exposing only ready-to-use ChatBot-specific * methods. From 197a8ca96da773d93c6737c47b856dae3e498bfb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:44:26 +0300 Subject: [PATCH 439/492] Use less important log level --- .../java/io/spine/chatbot/google/chat/GoogleChat.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java index 2ca388c8..b4130e4d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java @@ -51,12 +51,12 @@ final class GoogleChat implements GoogleChatClient, Logging { @Override public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { var repo = build.getRepository(); - var debug = _debug(); - debug.log("Building state update message for the repository `%s`.", repo); + var trace = _trace(); + trace.log("Building state update message for the repository `%s`.", repo); var message = buildStateMessage(build, thread); - debug.log("Sending state update message for the repository `%s`.", repo); + trace.log("Sending state update message for the repository `%s`.", repo); var sentMessage = sendMessage(build.getSpace(), message); - debug.log( + trace.log( "Build state update message with ID `%s` for the repository `%s` sent to the thread `%s`.", sentMessage.getName(), repo, sentMessage.getThread() .getName() From 039f71872877861b4bbacb6fbb3c7d2c5638bd73 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:45:14 +0300 Subject: [PATCH 440/492] Use commonly-used `Factory` suffix instead of `Provider` --- .../java/io/spine/chatbot/google/chat/GoogleChatClient.java | 4 +--- .../{HangoutsChatProvider.java => HangoutsChatFactory.java} | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/google/chat/{HangoutsChatProvider.java => HangoutsChatFactory.java} (95%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java index 1a4b9664..469d38cf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatClient.java @@ -24,8 +24,6 @@ import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.thread.ThreadResource; -import static io.spine.chatbot.google.chat.HangoutsChatProvider.newHangoutsChat; - /** * A client to the Google Chat server. * @@ -49,6 +47,6 @@ public interface GoogleChatClient { *

      The client is backed by {@link HangoutsChat} API. */ static GoogleChatClient newInstance() { - return new GoogleChat(newHangoutsChat()); + return new GoogleChat(HangoutsChatFactory.newInstance()); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatProvider.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatFactory.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatProvider.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatFactory.java index de6ff898..418aacd5 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatProvider.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/HangoutsChatFactory.java @@ -35,20 +35,20 @@ /** * Provides fully-configured {@link HangoutsChat chat} client. */ -final class HangoutsChatProvider { +final class HangoutsChatFactory { private static final String BOT_NAME = "Spine ChatBot"; /** * Prevents direct instantiation of the utility class. */ - private HangoutsChatProvider() { + private HangoutsChatFactory() { } /** * Creates a new instance of the {@link HangoutsChat} client. */ - static HangoutsChat newHangoutsChat() { + static HangoutsChat newInstance() { var credentials = chatServiceAccountKey().toCredentials(); var credentialsAdapter = new HttpCredentialsAdapter(credentials); var chat = chatWithCredentials(credentialsAdapter) From 507080f5cc20e7ee2ce3f5227dca1ebdf17eb04a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:46:09 +0300 Subject: [PATCH 441/492] Replace backticks with {@code} --- .../java/io/spine/chatbot/server/github/BuildStateMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java index 5b35a0be..42262853 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -45,7 +45,7 @@ public interface BuildStateMixin extends BuildOrBuilder { /** * Determines whether the build is failed. * - * @return `true` if the build is failed, `false` otherwise + * @return {@code true} if the build is failed, {@code false} otherwise * @see #failed(Build.State) */ default boolean failed() { From 4e4f33c241f85e043b93fa517cd6bcb275f1a91e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:47:12 +0300 Subject: [PATCH 442/492] Use `;` to separate list items --- .../src/main/java/io/spine/chatbot/Application.java | 2 +- .../java/io/spine/chatbot/server/github/BuildStateMixin.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index e703f4a0..dabab6ef 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -32,7 +32,7 @@ *

      The application exposes a number of REST endpoints accessible for the clients such as: * *

        - *
      • {@code /chat/incoming/event} — handles incoming events from the Google Chat space. + *
      • {@code /chat/incoming/event} — handles incoming events from the Google Chat space; *
      • {@code /repositories/check} — triggers checking of the repositories build statuses. *
      * diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java index 42262853..677f7043 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java @@ -95,9 +95,9 @@ default BuildStateChange.Type stateChangeFrom(BuildStateMixin previousState) { *

      The status is considered: * *

        - *
      • {@code failed} if the new state is {@link #failed() failed}. + *
      • {@code failed} if the new state is {@link #failed() failed}; *
      • {@code recovered} if the new state is {@code passed} and the previous is - * {@link #failed() failed}. + * {@link #failed() failed}; *
      • {@code stable} if the new state is {@code passed} and the previous is either * {@code unknown} meaning that there were no previous states or {@code passed} as well. *
      From d2f1984d713eecef2ac9f991c927ca275292905b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:47:53 +0300 Subject: [PATCH 443/492] Drop the nouns --- .../chatbot/server/google/chat/IncomingEventsHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 738b06e4..d697dddf 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -37,9 +37,7 @@ import static io.spine.chatbot.server.google.chat.ChatEvents.toMessageReceived; /** - * Google Chat incoming events reactor. - * - *

      Processes incoming {@link ChatEvent} message and emits one of the following domain events: + * Processes incoming {@link ChatEvent} message and emits one of the following domain events: * *

        *
      • {@link BotAddedToSpace} — the ChatBot is added to a space; From 8a12b91957a495cc69a90787ce1e9665111e7f86 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:48:58 +0300 Subject: [PATCH 444/492] Pluralize `*Identifier` --- .../io/spine/chatbot/google/chat/GoogleChat.java | 4 ++-- ...{GitHubIdentifier.java => GitHubIdentifiers.java} | 4 ++-- .../chatbot/server/github/SpineOrgInitProcess.java | 4 ++-- .../spine/chatbot/server/google/chat/ChatEvents.java | 2 +- ...hatIdentifier.java => GoogleChatIdentifiers.java} | 4 ++-- .../server/google/chat/ThreadChatRepository.java | 2 +- .../server/google/chat/incoming/SpaceMixin.java | 2 +- ...dentifierTest.java => GitHubIdentifiersTest.java} | 10 +++++----- .../server/github/OrgReposProjectionTest.java | 6 +++--- .../server/github/OrganizationAggregateTest.java | 4 ++-- .../chatbot/server/github/RepoBuildProcessTest.java | 6 +++--- .../server/github/RepositoryAggregateTest.java | 4 ++-- .../server/github/SpineOrgInitProcessTest.java | 2 +- ...ifierTest.java => GoogleChatIdentifiersTest.java} | 12 ++++++------ .../google/chat/IncomingEventsHandlerTest.java | 4 ++-- .../server/google/chat/SpaceAggregateTest.java | 2 +- .../server/google/chat/ThreadAggregateTest.java | 6 +++--- .../server/google/chat/ThreadChatProcessTest.java | 8 ++++---- 18 files changed, 43 insertions(+), 43 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/server/github/{GitHubIdentifier.java => GitHubIdentifiers.java} (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/{GoogleChatIdentifier.java => GoogleChatIdentifiers.java} (96%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/github/{GitHubIdentifierTest.java => GitHubIdentifiersTest.java} (81%) rename google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/{GoogleChatIdentifierTest.java => GoogleChatIdentifiersTest.java} (93%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java index b4130e4d..6ab13e8d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java @@ -30,8 +30,8 @@ import java.io.IOException; import static io.spine.chatbot.google.chat.BuildStateUpdates.buildStateMessage; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; import static io.spine.util.Exceptions.newIllegalStateException; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifiers.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifiers.java index 44a49664..afcffe36 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifiers.java @@ -28,12 +28,12 @@ /** * A utility for working with {@link GitHubContext} identifiers. */ -public final class GitHubIdentifier { +public final class GitHubIdentifiers { /** * Prevents instantiation of this utility class. */ - private GitHubIdentifier() { + private GitHubIdentifiers() { } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 014e6a3c..243fdeab 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -42,8 +42,8 @@ import io.spine.server.procman.ProcessManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.chatbot.server.github.GitHubIdentifier.repository; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java index 6b253d30..114add06 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java @@ -26,7 +26,7 @@ import io.spine.chatbot.google.chat.incoming.event.MessageReceived; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; /** * A utility for working with {@link ChatEvent}s. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiers.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java rename to google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiers.java index 83d0bbb6..62c7ca6c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifier.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiers.java @@ -29,12 +29,12 @@ /** * A utility for working with {@link GoogleChatContext} identifiers. */ -public final class GoogleChatIdentifier { +public final class GoogleChatIdentifiers { /** * Prevents instantiation of this utility class. */ - private GoogleChatIdentifier() { + private GoogleChatIdentifiers() { } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 93d3f7f1..31f44481 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -34,7 +34,7 @@ import java.util.Set; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; import static io.spine.server.route.EventRoute.withId; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java index 4ee964e0..5ad27459 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java @@ -25,7 +25,7 @@ import io.spine.chatbot.google.chat.incoming.SpaceOrBuilder; import io.spine.chatbot.google.chat.incoming.SpaceType; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; /** * Provides utility helpers for the {@link io.spine.chatbot.google.chat.incoming.Space Space} type. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java similarity index 81% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java index e621aeba..2c7db7ce 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java @@ -20,14 +20,14 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.server.google.chat.GoogleChatIdentifier; +import io.spine.chatbot.server.google.chat.GoogleChatIdentifiers; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; -@DisplayName("`GitHubIdentifier` should") -final class GitHubIdentifierTest extends UtilityClassTest { +@DisplayName("`GitHubIdentifiers` should") +final class GitHubIdentifiersTest extends UtilityClassTest { - GitHubIdentifierTest() { - super(GoogleChatIdentifier.class); + GitHubIdentifiersTest() { + super(GoogleChatIdentifiers.class); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index 66d6e943..6b73e8c8 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -35,9 +35,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index a307b5ce..898a82a2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -33,8 +33,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index f73e1d96..c735b8f4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -40,10 +40,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.chatbot.server.github.GitHubIdentifier.repository; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.server.github.RepoBuildProcess.buildFrom; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`RepoBuildProcess` should") final class RepoBuildProcessTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 99c2bddf..a4e2897a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -32,8 +32,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.organization; -import static io.spine.chatbot.server.github.GitHubIdentifier.repository; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.url.MoreUrls.githubUrlFor; import static io.spine.chatbot.url.MoreUrls.travisUrlFor; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 5b783eb1..43775c20 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -32,7 +32,7 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.SpineOrgInitProcess.ORGANIZATION; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`SpineOrgInitProcess` should") final class SpineOrgInitProcessTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java similarity index 93% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java index 1872e71d..d0cf2e06 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifierTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java @@ -34,16 +34,16 @@ import java.util.stream.Stream; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -@DisplayName("`GoogleChatIdentifier` should") -final class GoogleChatIdentifierTest extends UtilityClassTest { +@DisplayName("`GoogleChatIdentifiers` should") +final class GoogleChatIdentifiersTest extends UtilityClassTest { - GoogleChatIdentifierTest() { - super(GoogleChatIdentifier.class); + GoogleChatIdentifiersTest() { + super(GoogleChatIdentifiers.class); } // nested tests do not work with static classes diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index 777220b1..bdbb0e05 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -37,8 +37,8 @@ import static io.spine.chatbot.google.chat.incoming.EventType.MESSAGE; import static io.spine.chatbot.google.chat.incoming.EventType.REMOVED_FROM_SPACE; import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`IncomingEventsHandler` should") final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index a1b50681..581cbc18 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -35,7 +35,7 @@ import static io.spine.chatbot.google.chat.incoming.EventType.ADDED_TO_SPACE; import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`SpaceAggregate` should") final class SpaceAggregateTest extends GoogleChatContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 035c4f2f..69005106 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -34,9 +34,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @DisplayName("`ThreadAggregate` should") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index cce842d3..da5066be 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -37,10 +37,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifier.repository; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.space; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifier.thread; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @DisplayName("`ThreadChatProcess` should") From 7d47a6c8982048c2de9bea7091f640d568709031 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:49:40 +0300 Subject: [PATCH 445/492] Fix misprint --- .../chatbot/server/google/chat/IncomingEventsHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index d697dddf..19df3613 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -37,7 +37,7 @@ import static io.spine.chatbot.server.google.chat.ChatEvents.toMessageReceived; /** - * Processes incoming {@link ChatEvent} message and emits one of the following domain events: + * Processes incoming {@link ChatEvent} messages and emits one of the following domain events: * *
          *
        • {@link BotAddedToSpace} — the ChatBot is added to a space; @@ -52,7 +52,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Logging { /** - * Processes incoming external {@link ChatEvent}. + * Processes an incoming external {@link ChatEvent}. * *

          If the event type is not supported, returns {@link #nothing() nothing}. */ From 31f68cdd9f563d478ee64acc925b6f20062127fb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:50:50 +0300 Subject: [PATCH 446/492] Lower log level --- .../spine/chatbot/server/google/chat/IncomingEventsHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java index 19df3613..d5471d56 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/IncomingEventsHandler.java @@ -63,7 +63,7 @@ final class IncomingEventsHandler extends AbstractEventReactor implements Loggin var space = chatEvent.getSpace(); switch (chatEvent.getType()) { case MESSAGE: - _info().log("A new user message received in the space `%s` (%s).", + _debug().log("A new user message received in the space `%s` (%s).", space.getDisplayName(), space.getName()); return EitherOf4.withC(toMessageReceived(chatEvent)); case ADDED_TO_SPACE: From aacc969cfcea3b3482ca0d41087730f20b6d5c1b Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:51:11 +0300 Subject: [PATCH 447/492] Fix article usage --- .../io/spine/chatbot/server/google/chat/ThreadAggregate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index 5c3cb8b2..38112cb8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -32,7 +32,7 @@ import io.spine.server.event.React; /** - * A thread in the chat room. + * A thread in a chat room. * *

          A new thread is initialized as early as a new conversation is started in the room. * It happens once the first message is posted to the conversation. From 84bb4036d568e87cb9dfa7f6506bc3dc39f21adc Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:51:42 +0300 Subject: [PATCH 448/492] Improve link name --- .../src/main/java/io/spine/chatbot/travis/BuildsQuery.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java index 25ef3842..175e58d7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java @@ -25,7 +25,7 @@ /** * A branch builds query to the Travis CI API. * - * @see Find branch build + * @see Finding the branch build */ public final class BuildsQuery extends Query { From b05249e052936d8f6b82a0eb0fae9b028c2a4360 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:52:45 +0300 Subject: [PATCH 449/492] Use {@linkplain} over {@link} when monospace formatting is not required. --- google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java | 2 +- .../main/java/io/spine/chatbot/google/chat/package-info.java | 2 +- .../src/main/java/io/spine/chatbot/package-info.java | 2 +- .../main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 190a9cff..2bb8395a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -43,7 +43,7 @@ final class BeanFactory { /** - * Registers {@link PubsubPushRequest push request} Jackson deserializer. + * Registers {@linkplain PubsubPushRequest push request} Jackson deserializer. */ @Singleton @Bean diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java index d242bf94..a2382aea 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/package-info.java @@ -22,7 +22,7 @@ * This package contains Google Chat API facade. * *

          The usage of the Chat API itself it not straightforward. That's why it is recommended to - * use the {@link io.spine.chatbot.google.chat.GoogleChatClient facade} instead. + * use the {@linkplain io.spine.chatbot.google.chat.GoogleChatClient facade} instead. */ @CheckReturnValue @ParametersAreNonnullByDefault diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java index d1c87156..f74c9fd4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/package-info.java @@ -19,7 +19,7 @@ */ /** - * This contains package the application {@link io.spine.chatbot.Application entry point}. + * This contains package the application {@linkplain io.spine.chatbot.Application entry point}. */ @CheckReturnValue @ParametersAreNonnullByDefault diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java index a8ef0599..e7b11807 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java @@ -32,7 +32,7 @@ /** * Converts the incoming JSON strings into Protobuf messages relying on the Spine - * {@link Json conversion functionality}. + * {@linkplain Json conversion functionality}. * * @param * the Protobuf message supplied in the response body From bc77beb4a16e9c40a4b10dddc81dd110f697e4f7 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:58:20 +0300 Subject: [PATCH 450/492] Move not-null check to a separate line --- .../java/io/spine/chatbot/travis/JsonProtoBodyHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java index e7b11807..9ae2667e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/JsonProtoBodyHandler.java @@ -49,7 +49,8 @@ private JsonProtoBodyHandler(Class type) { * Creates a body handler for a specified Protobuf message. */ static JsonProtoBodyHandler jsonBodyHandler(Class type) { - return new JsonProtoBodyHandler<>(checkNotNull(type)); + checkNotNull(type); + return new JsonProtoBodyHandler<>(type); } @Override From d99849cdedc09f3b23dc0c4efbc696dd944ecd5c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 17:59:01 +0300 Subject: [PATCH 451/492] Add missing articles --- .../src/main/java/io/spine/chatbot/travis/TravisClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java index 7043996d..dcd181be 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/TravisClient.java @@ -30,7 +30,7 @@ public interface TravisClient { /** - * Executes supplied {@code query} and returns response of type {@code T}. + * Executes the supplied {@code query} and returns the response of type {@code T}. * * @param query * query to execute From 57d011261369fd8a379b42c2fc2ab0eeee2e134d Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:01:16 +0300 Subject: [PATCH 452/492] Move MoreUrls to `.net` package --- .../main/java/io/spine/chatbot/{url => net}/MoreUrls.java | 2 +- .../java/io/spine/chatbot/{url => net}/package-info.java | 2 +- .../io/spine/chatbot/server/github/RepoBuildProcess.java | 2 +- .../spine/chatbot/server/github/SpineOrgInitProcess.java | 4 ++-- .../java/io/spine/chatbot/{url => net}/MoreUrlsTest.java | 8 ++++---- .../chatbot/server/github/OrgReposProjectionTest.java | 4 ++-- .../chatbot/server/github/OrganizationAggregateTest.java | 4 ++-- .../chatbot/server/github/RepositoryAggregateTest.java | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{url => net}/MoreUrls.java (98%) rename google-chat-bot/src/main/java/io/spine/chatbot/{url => net}/package-info.java (97%) rename google-chat-bot/src/test/java/io/spine/chatbot/{url => net}/MoreUrlsTest.java (92%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java b/google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java similarity index 98% rename from google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java rename to google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java index 0d2ea164..5462d49f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/url/MoreUrls.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.url; +package io.spine.chatbot.net; import io.spine.net.Url; import io.spine.net.Urls; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/url/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/net/package-info.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/url/package-info.java rename to google-chat-bot/src/main/java/io/spine/chatbot/net/package-info.java index d12cebc3..f825e52b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/url/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/net/package-info.java @@ -23,7 +23,7 @@ */ @CheckReturnValue @ParametersAreNonnullByDefault -package io.spine.chatbot.url; +package io.spine.chatbot.net; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 2e6e913d..06e661b4 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -44,7 +44,7 @@ import io.spine.server.tuple.EitherOf3; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.url.MoreUrls.travisBuildUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisBuildUrlFor; import static io.spine.protobuf.Messages.isDefault; import static io.spine.util.Exceptions.newIllegalStateException; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 243fdeab..47ba870c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -44,8 +44,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; -import static io.spine.chatbot.url.MoreUrls.githubUrlFor; -import static io.spine.chatbot.url.MoreUrls.travisUrlFor; +import static io.spine.chatbot.net.MoreUrls.githubUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisUrlFor; /** * Spine organization init process. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java similarity index 92% rename from google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java index e08dd459..cc91b70a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/url/MoreUrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.url; +package io.spine.chatbot.net; import io.spine.net.Urls; import io.spine.testing.UtilityClassTest; @@ -27,9 +27,9 @@ import org.junit.jupiter.api.Test; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.chatbot.url.MoreUrls.githubUrlFor; -import static io.spine.chatbot.url.MoreUrls.travisBuildUrlFor; -import static io.spine.chatbot.url.MoreUrls.travisUrlFor; +import static io.spine.chatbot.net.MoreUrls.githubUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisBuildUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @DisplayName("`MoreUrls` should") final class MoreUrlsTest extends UtilityClassTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index 6b73e8c8..bb325686 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -38,8 +38,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; -import static io.spine.chatbot.url.MoreUrls.githubUrlFor; -import static io.spine.chatbot.url.MoreUrls.travisUrlFor; +import static io.spine.chatbot.net.MoreUrls.githubUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @DisplayName("`OrgReposProjection` should") final class OrgReposProjectionTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 898a82a2..76114843 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -35,8 +35,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; -import static io.spine.chatbot.url.MoreUrls.githubUrlFor; -import static io.spine.chatbot.url.MoreUrls.travisUrlFor; +import static io.spine.chatbot.net.MoreUrls.githubUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @DisplayName("`OrganizationAggregate` should") final class OrganizationAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index a4e2897a..1554df00 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -34,8 +34,8 @@ import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; -import static io.spine.chatbot.url.MoreUrls.githubUrlFor; -import static io.spine.chatbot.url.MoreUrls.travisUrlFor; +import static io.spine.chatbot.net.MoreUrls.githubUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @DisplayName("`RepositoryAggregate` should") final class RepositoryAggregateTest extends GitHubContextAwareTest { From 9abf2816a845a6eb2d72688f2015344e91bc8d6f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:12:23 +0300 Subject: [PATCH 453/492] Use `Slug` to create URLs --- .../java/io/spine/chatbot/net/MoreUrls.java | 18 ++++++++++-------- .../server/github/RepoBuildProcess.java | 6 +++--- .../server/github/SpineOrgInitProcess.java | 17 +++++++++-------- .../io/spine/chatbot/net/MoreUrlsTest.java | 4 +++- .../server/github/OrgReposProjectionTest.java | 12 ++++++------ .../github/OrganizationAggregateTest.java | 4 ++-- .../server/github/RepositoryAggregateTest.java | 4 ++-- 7 files changed, 35 insertions(+), 30 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java b/google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java index 5462d49f..52fefc56 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/net/MoreUrls.java @@ -20,11 +20,11 @@ package io.spine.chatbot.net; +import io.spine.chatbot.github.Slug; import io.spine.net.Url; import io.spine.net.Urls; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; import static io.spine.util.Preconditions2.checkPositive; import static java.lang.String.format; @@ -46,27 +46,29 @@ private MoreUrls() { * Creates a new Travis CI build URL for a build with the specified {@code buildId} of * the repository with the specified {@code slug}. */ - public static Url travisBuildUrlFor(String slug, long buildId) { - checkNotEmptyOrBlank(slug); - var spec = format("%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, slug, checkPositive(buildId)); + public static Url travisBuildUrlFor(Slug slug, long buildId) { + checkNotNull(slug); + var spec = format( + "%s/%s/builds/%d", TRAVIS_GITHUB_ENDPOINT, slug.getValue(), checkPositive(buildId) + ); return Urls.create(spec); } /** * Creates a new Travis CI URL. */ - public static Url travisUrlFor(String slug) { + public static Url travisUrlFor(Slug slug) { checkNotNull(slug); - var spec = format("%s/%s", TRAVIS_GITHUB_ENDPOINT, slug); + var spec = format("%s/%s", TRAVIS_GITHUB_ENDPOINT, slug.getValue()); return Urls.create(spec); } /** * Creates a new GitHub URL. */ - public static Url githubUrlFor(String slug) { + public static Url githubUrlFor(Slug slug) { checkNotNull(slug); - var spec = format("%s/%s", GITHUB, slug); + var spec = format("%s/%s", GITHUB, slug.getValue()); return Urls.create(spec); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 06e661b4..23488f6f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -163,8 +163,8 @@ EitherOf3 handle(CheckReposito @VisibleForTesting static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { var branchBuildName = branchBuild.getName(); - var slug = branchBuild.getRepository() - .getSlug(); + var slug = Slugs.create(branchBuild.getRepository() + .getSlug()); var build = branchBuild.getLastBuild(); return Build .newBuilder() @@ -176,7 +176,7 @@ static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { .setLastCommit(from(build.getCommit())) .setCreatedBy(build.getCreatedBy() .getLogin()) - .setRepository(Slugs.create(slug)) + .setRepository(slug) .setTravisCiUrl(travisBuildUrlFor(slug, build.getId())) .vBuild(); } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 47ba870c..48b50148 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -42,10 +42,10 @@ import io.spine.server.procman.ProcessManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; /** * Spine organization init process. @@ -96,8 +96,8 @@ Iterable on(@External SpaceRegistered e) { } private RegisterRepository registerRepoCommand(Repository repo, OrganizationId org) { - var slug = repo.getSlug(); - _info().log("Registering `%s` repository.", slug); + var slug = Slugs.create(repo.getSlug()); + _info().log("Registering `%s` repository.", slug.getValue()); var header = RepoHeader .newBuilder() .setOrganization(org) @@ -107,19 +107,20 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o .vBuild(); return RegisterRepository .newBuilder() - .setId(repository(slug)) + .setId(repository(slug.getValue())) .setHeader(header) .vBuild(); } private RegisterOrganization registerOrgCommand(OrganizationId spineOrg, SpaceId space) { - _info().log("Registering `%s` organization.", ORGANIZATION.getValue()); + var slug = Slugs.forOrg(spineOrg); + _info().log("Registering `%s` organization.", spineOrg.getValue()); var header = OrgHeader .newBuilder() .setName("Spine Event Engine") .setWebsite(Urls.create("https://spine.io/")) - .setTravisProfile(travisUrlFor(ORGANIZATION.getValue())) - .setGithubProfile(githubUrlFor(ORGANIZATION.getValue())) + .setTravisProfile(travisUrlFor(slug)) + .setGithubProfile(githubUrlFor(slug)) .setSpace(space) .vBuild(); return RegisterOrganization diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java index cc91b70a..3a4f4df7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java @@ -20,6 +20,8 @@ package io.spine.chatbot.net; +import io.spine.chatbot.github.Slug; +import io.spine.chatbot.server.github.Slugs; import io.spine.net.Urls; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; @@ -34,7 +36,7 @@ @DisplayName("`MoreUrls` should") final class MoreUrlsTest extends UtilityClassTest { - private static final String REPO_SLUG = "SpineEventEngine/chat-bot"; + private static final Slug REPO_SLUG = Slugs.create("SpineEventEngine/chat-bot"); MoreUrlsTest() { super(MoreUrls.class); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index bb325686..b7a90a05 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -35,11 +35,11 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.net.MoreUrls.githubUrlFor; +import static io.spine.chatbot.net.MoreUrls.travisUrlFor; import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; -import static io.spine.chatbot.net.MoreUrls.githubUrlFor; -import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @DisplayName("`OrgReposProjection` should") final class OrgReposProjectionTest extends GitHubContextAwareTest { @@ -53,8 +53,8 @@ final class RegisterOrg { private final SpaceId googleChatSpace = space("spaces/qwdp123tt1"); private final OrganizationId organization = organization("OurOrg"); - private final Url githubUrl = githubUrlFor(organization.getValue()); - private final Url travisCiUrl = travisUrlFor(organization.getValue()); + private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); + private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(organization)); private final Url websiteUrl = Urls.create("https://our-organization.com"); private final OrgHeader header = OrgHeader @@ -98,8 +98,8 @@ final class RegisterRepo { private final OrganizationId organization = organization("MultiRepoOrg"); private final RepositoryId repository = repository("main-repo"); - private final Url githubUrl = githubUrlFor(organization.getValue()); - private final Url travisCiUrl = travisUrlFor(organization.getValue()); + private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); + private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(organization)); private final Url websiteUrl = Urls.create("https://multi-repo-organization.com"); private final OrgHeader orgHeader = OrgHeader diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 76114843..62ea4046 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -50,8 +50,8 @@ final class Register { private final SpaceId googleChatSpace = space("spaces/qwdp123ttQ"); private final OrganizationId organization = organization("TestOrganization"); - private final Url githubUrl = githubUrlFor(organization.getValue()); - private final Url travisCiUrl = travisUrlFor(organization.getValue()); + private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); + private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(organization)); private final Url websiteUrl = Urls.create("https://test-organization.com"); private final OrgHeader header = OrgHeader diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 1554df00..09652379 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -51,8 +51,8 @@ final class Register { private final RepositoryId repository = repository(REPO_SLUG); private final OrganizationId organization = organization(ORG_SLUG); - private final Url githubUrl = githubUrlFor(REPO_SLUG); - private final Url travisCiUrl = travisUrlFor(REPO_SLUG); + private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); + private final Url travisCiUrl = travisUrlFor(Slugs.forRepo(repository)); private final RepoHeader header = RepoHeader .newBuilder() .setGithubProfile(githubUrl) From c3508d17d1def649b1b250dee9bcb1e67d097868 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:15:27 +0300 Subject: [PATCH 454/492] Rename `last_status_check` to `when_last_checked` --- .../java/io/spine/chatbot/server/github/RepoBuildProcess.java | 2 +- .../src/main/proto/spine/chatbot/github/repository_build.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 23488f6f..5cf2242f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -91,7 +91,7 @@ EitherOf3 handle(CheckReposito .build(); } var build = buildFrom(branchBuild, c.getSpace()); - builder().setLastStatusCheck(Time.currentTime()) + builder().setWhenLastChecked(Time.currentTime()) .setBuild(build) .setCurrentState(build.getState()); var stateChange = BuildStateChange diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 001f9e83..1c107c56 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -45,7 +45,7 @@ message RepositoryBuild { RepositoryId repository = 1; // The time of the last status check. - .google.protobuf.Timestamp last_status_check = 2; + .google.protobuf.Timestamp when_last_checked = 2; // The current build. Build build = 3; From 98d9992174a617d83cff9c1744374cc3b27d29d2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:16:25 +0300 Subject: [PATCH 455/492] Use shortcut name qualifiers when possible --- .../src/main/proto/spine/chatbot/github/organization.proto | 2 +- .../src/main/proto/spine/chatbot/github/organization_init.proto | 2 +- .../proto/spine/chatbot/github/organization_init_commands.proto | 2 +- .../src/main/proto/spine/chatbot/github/repository_build.proto | 2 +- .../proto/spine/chatbot/github/repository_build_commands.proto | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index 97284a92..f429c5e6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -62,5 +62,5 @@ message OrgHeader { spine.net.Url travis_profile = 4 [(required) = true]; // The Google Chat space associated with the organization. - spine.chatbot.google.chat.SpaceId space = 5 [(required) = true, (validate) = true]; + google.chat.SpaceId space = 5 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index 1ad2e408..842433f9 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -45,7 +45,7 @@ message OrganizationInit { OrganizationId organization = 1; // The Google Chat space associated with the organization. - spine.chatbot.google.chat.SpaceId space = 2; + google.chat.SpaceId space = 2; // Determines whether the organization resources are already initialized. bool initialized = 3; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto index 638f6506..c9406565 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init_commands.proto @@ -43,5 +43,5 @@ message InitializeOrganization { OrganizationId organization = 1 [(required) = true]; // The Google Chat space associated with the organization. - spine.chatbot.google.chat.SpaceId space = 2 [(required) = true, (validate) = true]; + google.chat.SpaceId space = 2 [(required) = true, (validate) = true]; } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 1c107c56..5a98ff15 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -115,7 +115,7 @@ message Build { Slug repository = 8; // The Google Chat space associated with the organization. - spine.chatbot.google.chat.SpaceId space = 9 [(required) = true, (validate) = true]; + google.chat.SpaceId space = 9 [(required) = true, (validate) = true]; } // A git commit. diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto index c3afa662..a2658b3b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_commands.proto @@ -43,5 +43,5 @@ message CheckRepositoryBuild { OrganizationId organization = 2 [(required) = true]; // The Google Chat space associated with the organization. - spine.chatbot.google.chat.SpaceId space = 3 [(required) = true, (validate) = true]; + google.chat.SpaceId space = 3 [(required) = true, (validate) = true]; } From 31941792c2288eca1ba40ff54a49484639b79af4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:18:20 +0300 Subject: [PATCH 456/492] Do not expose aggregates and PMs. We currently do not query them, so the visibility could be set to None. --- .../src/main/proto/spine/chatbot/github/organization.proto | 2 +- .../src/main/proto/spine/chatbot/github/organization_init.proto | 2 +- .../src/main/proto/spine/chatbot/github/repository.proto | 2 +- .../src/main/proto/spine/chatbot/github/repository_build.proto | 2 +- .../src/main/proto/spine/chatbot/google/chat/space.proto | 2 +- .../src/main/proto/spine/chatbot/google/chat/thread.proto | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index f429c5e6..3cd7cf48 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -37,7 +37,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A GitHub organization. message Organization { - option (entity) = {kind: AGGREGATE visibility: FULL}; + option (entity) = {kind: AGGREGATE visibility: NONE}; option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; OrganizationId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index 842433f9..dba36dc9 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -39,7 +39,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // for a particular Chat Space. // message OrganizationInit { - option (entity) = {kind: PROCESS_MANAGER visibility: FULL}; + option (entity) = {kind: PROCESS_MANAGER visibility: NONE}; // The organization for which the initialization is performed. OrganizationId organization = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index d3d592ad..d262010e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -35,7 +35,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub repository. message Repository { - option (entity) = {kind: AGGREGATE visibility: FULL}; + option (entity) = {kind: AGGREGATE visibility: NONE}; option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; RepositoryId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index 5a98ff15..ae6081be 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -40,7 +40,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A build process of a GitHub repository. message RepositoryBuild { - option (entity) = {kind: PROCESS_MANAGER visibility: FULL}; + option (entity) = {kind: PROCESS_MANAGER visibility: NONE}; RepositoryId repository = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 45078212..4cac3ffa 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -34,7 +34,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A room or DM in Chat. message Space { - option (entity) = {kind: AGGREGATE visibility: FULL}; + option (entity) = {kind: AGGREGATE visibility: NONE}; option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; SpaceId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index e692b8bf..4ffe7e23 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -34,7 +34,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A thread in a room. message Thread { - option (entity) = {kind: AGGREGATE visibility: FULL}; + option (entity) = {kind: AGGREGATE visibility: NONE}; ThreadId id = 1; From 3ef383aa183330885a4f04721006fb3c7a356b19 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:21:33 +0300 Subject: [PATCH 457/492] Use singular form for `repeated` fields --- .../io/spine/chatbot/server/google/chat/ThreadAggregate.java | 2 +- .../src/main/proto/spine/chatbot/google/chat/thread.proto | 2 +- .../spine/chatbot/server/google/chat/ThreadAggregateTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java index 38112cb8..91f22811 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadAggregate.java @@ -77,6 +77,6 @@ MessageAdded on(MessageCreated e) { @Apply private void on(MessageAdded e) { - builder().addMessages(e.getMessage()); + builder().addMessage(e.getMessage()); } } diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto index 4ffe7e23..e0ad8ad4 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/thread.proto @@ -45,7 +45,7 @@ message Thread { SpaceId space = 3; // Messages posted by the bot to the thread. - repeated MessageId messages = 4; + repeated MessageId message = 4; } // Chat Thread resource. diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 69005106..1824f075 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -135,7 +135,7 @@ void settingState() { .setId(thread) .setSpace(space) .setResource(threadResource) - .addMessages(message) + .addMessage(message) .vBuild(); context().assertState(thread, Thread.class) .isEqualTo(state); From a88b343bc7031f22b423d967a35bed42cb8bc9f0 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:22:52 +0300 Subject: [PATCH 458/492] Rename FailFastAwareClient to CanFailFast --- .../chatbot/{FailFastAwareClient.java => CanFailFast.java} | 6 +++--- .../spine/chatbot/google/chat/InMemoryGoogleChatClient.java | 6 +++--- .../java/io/spine/chatbot/travis/InMemoryTravisClient.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) rename google-chat-bot/src/test/java/io/spine/chatbot/{FailFastAwareClient.java => CanFailFast.java} (93%) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/FailFastAwareClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java similarity index 93% rename from google-chat-bot/src/test/java/io/spine/chatbot/FailFastAwareClient.java rename to google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java index dfc80d06..07ae11ff 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/FailFastAwareClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java @@ -27,9 +27,9 @@ import static io.spine.util.Exceptions.newIllegalStateException; /** - * An abstract API client that exposes the {@code fail-fast} concept to the actual test clients. + * An abstract API that exposes the {@code fail-fast} concept. */ -public abstract class FailFastAwareClient implements Logging { +public abstract class CanFailFast implements Logging { /** Determines whether the client should fail if a particular response is not preconfigured. **/ private final boolean failFast; @@ -37,7 +37,7 @@ public abstract class FailFastAwareClient implements Logging { /** * Creates a new client with the specified {@code failFast} behavior. */ - protected FailFastAwareClient(boolean failFast) { + protected CanFailFast(boolean failFast) { this.failFast = failFast; } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java index 9c1b0b37..89641510 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java @@ -20,7 +20,7 @@ package io.spine.chatbot.google.chat; -import io.spine.chatbot.FailFastAwareClient; +import io.spine.chatbot.CanFailFast; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.thread.ThreadResource; @@ -32,7 +32,7 @@ /** * An in-memory test-only implementation of the Google Chat client. */ -public final class InMemoryGoogleChatClient extends FailFastAwareClient implements GoogleChatClient { +public final class InMemoryGoogleChatClient extends CanFailFast implements GoogleChatClient { private final Map sentMessages = new ConcurrentHashMap<>(); @@ -41,7 +41,7 @@ private InMemoryGoogleChatClient(boolean failFast) { } /** - * Creates a {@link #FailFastAwareClient#failFast failFast} in-memory Google Chat client. + * Creates a {@link #CanFailFast#failFast failFast} in-memory Google Chat client. */ public static InMemoryGoogleChatClient strictClient() { return new InMemoryGoogleChatClient(true); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java index 0e1d90b4..666e1974 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java @@ -20,7 +20,7 @@ package io.spine.chatbot.travis; -import io.spine.chatbot.FailFastAwareClient; +import io.spine.chatbot.CanFailFast; import io.spine.chatbot.github.Slug; import java.util.Map; @@ -32,7 +32,7 @@ /** * An in-memory test-only implementation of the Travis CI API client. */ -public final class InMemoryTravisClient extends FailFastAwareClient implements TravisClient { +public final class InMemoryTravisClient extends CanFailFast implements TravisClient { private final Map, TravisResponse> responses = new ConcurrentHashMap<>(); @@ -41,7 +41,7 @@ private InMemoryTravisClient(boolean failFast) { } /** - * Creates a {@link #FailFastAwareClient#failFast failFast} in-memory Travis CI client. + * Creates a {@link #CanFailFast#failFast failFast} in-memory Travis CI client. */ public static InMemoryTravisClient strictClient() { return new InMemoryTravisClient(true); From 9abd461504cffac031a74d3fb2ff76fdbddc37fb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:27:04 +0300 Subject: [PATCH 459/492] Wrap referenced types into backticks --- .../chatbot/server/github/OrganizationAggregateTest.java | 2 +- .../spine/chatbot/server/github/RepoBuildProcessTest.java | 8 ++++---- .../chatbot/server/github/RepositoryAggregateTest.java | 2 +- .../chatbot/server/github/SpineOrgInitProcessTest.java | 2 +- .../chatbot/server/google/chat/SpaceAggregateTest.java | 8 ++++---- .../chatbot/server/google/chat/ThreadAggregateTest.java | 2 +- .../chatbot/server/google/chat/ThreadChatProcessTest.java | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 62ea4046..0af07a1f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -74,7 +74,7 @@ void registerOrganization() { } @Test - @DisplayName("producing OrganizationRegistered event") + @DisplayName("producing `OrganizationRegistered` event") void producingEvent() { var organizationRegistered = OrganizationRegistered .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index c735b8f4..a934b987 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -53,7 +53,7 @@ final class RepoBuildProcessTest extends GitHubContextAwareTest { private static final SpaceId chatSpace = space("spaces/1245wrq"); @Test - @DisplayName("throw NoBuildsFound rejection when Travis API cannot return builds for a repo") + @DisplayName("throw `NoBuildsFound` rejection when Travis API cannot return builds for a repo") void throwNoBuildsFoundRejection() { travisClient().setBuildsFor(Slugs.forRepo(repository), RepoBranchBuildResponse.getDefaultInstance()); @@ -94,7 +94,7 @@ void sendCheckCommand() { } @Test - @DisplayName("producing BuildFailed event") + @DisplayName("producing `BuildFailed` event") void producingEvent() { var stateChange = BuildStateChange .newBuilder() @@ -157,7 +157,7 @@ void sendCheckCommands() { } @Test - @DisplayName("producing BuildRecovered event") + @DisplayName("producing `BuildRecovered` event") void producingEvent() { var stateChange = BuildStateChange .newBuilder() @@ -232,7 +232,7 @@ void sendCheckCommands() { } @Test - @DisplayName("producing BuildSucceededAgain event") + @DisplayName("producing `BuildSucceededAgain` event") void producingEvent() { var stateChange = BuildStateChange .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 09652379..476e7385 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -72,7 +72,7 @@ void registerRepository() { } @Test - @DisplayName("producing RepositoryRegistered event") + @DisplayName("producing `RepositoryRegistered` event") void producingEvent() { var repositoryRegistered = RepositoryRegistered .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 43775c20..70056d70 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -38,7 +38,7 @@ final class SpineOrgInitProcessTest extends GitHubContextAwareTest { @Nested - @DisplayName("perform initialization of watched spine resources") + @DisplayName("perform initialization of watched Spine resources") final class Init { private final SpaceId space = space("spaces/qjwrp1441"); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 581cbc18..51b26654 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -62,7 +62,7 @@ void registerSpace() { } @Test - @DisplayName("producing SpaceRegistered event") + @DisplayName("producing `SpaceRegistered` event") void producingEvent() { var spaceRegistered = SpaceRegistered .newBuilder() @@ -73,7 +73,7 @@ void producingEvent() { } @Test - @DisplayName("setting Space state") + @DisplayName("setting space state") void settingState() { var expectedState = Space .newBuilder() @@ -108,7 +108,7 @@ void addBotToSpace() { } @Test - @DisplayName("producing SpaceRegistered event") + @DisplayName("producing `SpaceRegistered` event") void producingEvent() { var spaceRegistered = SpaceRegistered .newBuilder() @@ -119,7 +119,7 @@ void producingEvent() { } @Test - @DisplayName("setting Space state") + @DisplayName("setting space state") void settingState() { var expectedState = Space .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 1824f075..25b8f79b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -117,7 +117,7 @@ void createThreadAndMessage() { } @Test - @DisplayName("producing MessageAdded event") + @DisplayName("producing `MessageAdded` event") void producingEvent() { var messageAdded = MessageAdded .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index da5066be..69e0adf0 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -114,7 +114,7 @@ abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, BuildStateChange stateChange); @Test - @DisplayName("producing MessageCreated and ThreadCreated events") + @DisplayName("producing `MessageCreated` and `ThreadCreated` events") void producingEvents() { var messageCreated = MessageCreated .newBuilder() From 12d187e628e7a7d1bc25411418e9c4c06a03064f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:27:16 +0300 Subject: [PATCH 460/492] Use Tests.nullRef instead of `null` directly --- .../chatbot/server/google/chat/GoogleChatContextTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java index 837e3a6b..89d8ccf9 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static io.spine.testing.Tests.nullRef; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -41,13 +42,13 @@ void allowConfiguringTravisClient() { ); } - @SuppressWarnings({"ResultOfMethodCallIgnored", "ConstantConditions"}) + @SuppressWarnings("ResultOfMethodCallIgnored") @Test @DisplayName("not allow passing `null` value as Google Chat client") void notAllowNullTravisClients() { assertThrows( NullPointerException.class, () -> GoogleChatContext.newBuilder() - .setClient(null) + .setClient(nullRef()) ); } } From 46247223c73cea5be10a66795d2e04de2e926a5a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:29:09 +0300 Subject: [PATCH 461/492] Use synchronized maps instead concurrent hash maps --- .../spine/chatbot/google/chat/InMemoryGoogleChatClient.java | 5 +++-- .../java/io/spine/chatbot/travis/InMemoryTravisClient.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java index 89641510..0ae0ab98 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/google/chat/InMemoryGoogleChatClient.java @@ -24,17 +24,18 @@ import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.google.chat.thread.ThreadResource; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Collections.synchronizedMap; /** * An in-memory test-only implementation of the Google Chat client. */ public final class InMemoryGoogleChatClient extends CanFailFast implements GoogleChatClient { - private final Map sentMessages = new ConcurrentHashMap<>(); + private final Map sentMessages = synchronizedMap(new HashMap<>()); private InMemoryGoogleChatClient(boolean failFast) { super(failFast); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java index 666e1974..bcda21f8 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java @@ -23,18 +23,19 @@ import io.spine.chatbot.CanFailFast; import io.spine.chatbot.github.Slug; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.protobuf.Messages.defaultInstance; +import static java.util.Collections.synchronizedMap; /** * An in-memory test-only implementation of the Travis CI API client. */ public final class InMemoryTravisClient extends CanFailFast implements TravisClient { - private final Map, TravisResponse> responses = new ConcurrentHashMap<>(); + private final Map, TravisResponse> responses = synchronizedMap(new HashMap<>()); private InMemoryTravisClient(boolean failFast) { super(failFast); From f1f63471ef39183c8e4ede3c8caf3144bf7f4b5c Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Tue, 14 Jul 2020 18:32:42 +0300 Subject: [PATCH 462/492] Make methods final where appropriate --- .../src/main/java/io/spine/chatbot/travis/Query.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java index bdf9e285..d197acce 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Query.java @@ -47,14 +47,14 @@ abstract class Query { /** * Returns the request URL to the REST endpoint. */ - String request() { + final String request() { return request; } /** * Returns query response type. */ - Class responseType() { + final Class responseType() { return responseType; } From 070fa31b9d1f4b926ba3a8042cb251b786b6d083 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 10:42:18 +0300 Subject: [PATCH 463/492] Use `nullRef` in tests instead of `null` --- .../io/spine/chatbot/PubsubPushRequestDeserializerTest.java | 3 ++- .../io/spine/chatbot/server/github/BuildStateMixinTest.java | 3 ++- .../io/spine/chatbot/server/github/GitHubContextTest.java | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java index 870ddd07..a8eebb7b 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java @@ -37,6 +37,7 @@ import java.nio.charset.StandardCharsets; import java.text.ParseException; +import static io.spine.testing.Tests.nullRef; import static io.spine.util.Exceptions.newIllegalStateException; @MicronautTest @@ -62,7 +63,7 @@ void deserializePubsubMessage() throws JsonProcessingException, ParseException { .setMessage(pubsubMessage) .vBuild(); - var mapper = mapperFactory.objectMapper(null, null); + var mapper = mapperFactory.objectMapper(nullRef(), nullRef()); var pushNotification = mapper.readValue(pushRequestJson(), PubsubPushRequest.class); ProtoTruth.assertThat(pushNotification) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java index df581387..3788e44c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.server.github.BuildStateMixin.buildStateFrom; +import static io.spine.testing.Tests.nullRef; import static org.junit.jupiter.api.Assertions.assertThrows; @DisplayName("`BuildStateMixin` should") @@ -33,7 +34,7 @@ final class BuildStateMixinTest { @Test @DisplayName("not accept `null` build states") void notAcceptNull() { - assertThrows(NullPointerException.class, () -> buildStateFrom(null)); + assertThrows(NullPointerException.class, () -> buildStateFrom(nullRef())); } @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java index ba57aab4..18337961 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static io.spine.testing.Tests.nullRef; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -40,13 +41,13 @@ void allowConfiguringTravisClient() { ); } - @SuppressWarnings({"ResultOfMethodCallIgnored", "ConstantConditions"}) + @SuppressWarnings("ResultOfMethodCallIgnored") @Test @DisplayName("not allow passing `null` value as Travis CI client") void notAllowNullTravisClients() { assertThrows( NullPointerException.class, () -> GitHubContext.newBuilder() - .setTravis(null) + .setTravis(nullRef()) ); } } From 06bfa5f88e4716829a1ee613d9b5ff88484963f1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 14:04:15 +0300 Subject: [PATCH 464/492] Use shorter params and variable names where possible --- .../java/io/spine/chatbot/BeanFactory.java | 3 +- .../server/github/RepoBuildProcess.java | 40 +++++----- .../server/github/SpineOrgInitRepository.java | 9 ++- .../server/google/chat/ThreadChatProcess.java | 6 +- .../chatbot/IncomingEventsControllerTest.java | 4 +- .../PubsubPushRequestDeserializerTest.java | 5 +- .../server/github/GitHubContextAwareTest.java | 8 +- .../server/github/OrgReposProjectionTest.java | 38 ++++----- .../server/github/RepoBuildProcessTest.java | 80 +++++++++---------- .../github/RepositoryAggregateTest.java | 34 ++++---- .../github/SpineOrgInitProcessTest.java | 8 +- .../chat/GoogleChatContextAwareTest.java | 8 +- .../chat/IncomingEventsHandlerTest.java | 14 ++-- .../google/chat/ThreadChatProcessTest.java | 18 ++--- .../chatbot/travis/InMemoryTravisClient.java | 6 +- 15 files changed, 140 insertions(+), 141 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java index 2bb8395a..c49a1989 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/BeanFactory.java @@ -90,7 +90,8 @@ public PubsubPushRequest deserialize(JsonParser parser, DeserializationContext c return result; } catch (IOException e) { throw newIllegalArgumentException( - e, "Unable to deserialize `PubsubPushRequest` json." + e, "Unable to deserialize `%s` json.", + PubsubPushRequest.class.getSimpleName() ); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 5cf2242f..c22515a0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -80,14 +80,14 @@ final class RepoBuildProcess @Assign EitherOf3 handle(CheckRepositoryBuild c) throws NoBuildsFound { - var repository = c.getRepository(); - _info().log("Checking build status for the repository `%s`.", repository.getValue()); - var branchBuild = client.execute(BuildsQuery.forRepo(Slugs.forRepo(repository))); + var repo = c.getRepository(); + _info().log("Checking build status for the repository `%s`.", repo.getValue()); + var branchBuild = client.execute(BuildsQuery.forRepo(Slugs.forRepo(repo))); if (isDefault(branchBuild.getLastBuild())) { - _warn().log("No builds found for the repository `%s`.", repository.getValue()); + _warn().log("No builds found for the repository `%s`.", repo.getValue()); throw NoBuildsFound .newBuilder() - .setRepository(repository) + .setRepository(repo) .build(); } var build = buildFrom(branchBuild, c.getSpace()); @@ -99,62 +99,62 @@ EitherOf3 handle(CheckReposito .setPreviousValue(state().getBuild()) .setNewValue(build) .vBuild(); - var result = determineOutcome(repository, stateChange); + var result = determineOutcome(repo, stateChange); return result; } private EitherOf3 - determineOutcome(RepositoryId repository, BuildStateChange stateChange) { + determineOutcome(RepositoryId repo, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); var previousBuildState = stateChange.getPreviousValue(); var stateStatusChange = newBuildState.stateChangeFrom(previousBuildState); switch (stateStatusChange) { case FAILED: - return onFailed(repository, stateChange); + return onFailed(repo, stateChange); case RECOVERED: - return onRecovered(repository, stateChange); + return onRecovered(repo, stateChange); case STABLE: - return onStable(repository, stateChange); + return onStable(repo, stateChange); case BSCT_UNKNOWN: case UNRECOGNIZED: default: throw newIllegalStateException( "Unexpected state status change `%s` for the repository `%s`.", - stateStatusChange, repository.getValue() + stateStatusChange, repo.getValue() ); } } private EitherOf3 - onStable(RepositoryId repository, BuildStateChange stateChange) { - _info().log("The build for the repository `%s` is stable.", repository.getValue()); + onStable(RepositoryId repo, BuildStateChange stateChange) { + _info().log("The build for the repository `%s` is stable.", repo.getValue()); var buildSucceededAgain = BuildSucceededAgain .newBuilder() - .setRepository(repository) + .setRepository(repo) .setChange(stateChange) .vBuild(); return EitherOf3.withC(buildSucceededAgain); } private EitherOf3 - onRecovered(RepositoryId repository, BuildStateChange stateChange) { - _info().log("The build for the repository `%s` is recovered.", repository.getValue()); + onRecovered(RepositoryId repo, BuildStateChange stateChange) { + _info().log("The build for the repository `%s` is recovered.", repo.getValue()); var buildRecovered = BuildRecovered .newBuilder() - .setRepository(repository) + .setRepository(repo) .setChange(stateChange) .vBuild(); return EitherOf3.withB(buildRecovered); } private EitherOf3 - onFailed(RepositoryId repository, BuildStateChange stateChange) { + onFailed(RepositoryId repo, BuildStateChange stateChange) { var newBuildState = stateChange.getNewValue(); _info().log("A build for the repository `%s` failed with the status `%s`.", - repository.getValue(), newBuildState.getState()); + repo.getValue(), newBuildState.getState()); var buildFailed = BuildFailed .newBuilder() - .setRepository(repository) + .setRepository(repo) .setChange(stateChange) .vBuild(); return EitherOf3.withA(buildFailed); diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java index 55f3f256..4685c839 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitRepository.java @@ -37,10 +37,10 @@ final class SpineOrgInitRepository extends ProcessManagerRepository { - private final TravisClient travisClient; + private final TravisClient client; - SpineOrgInitRepository(TravisClient travisClient) { - this.travisClient = travisClient; + SpineOrgInitRepository(TravisClient client) { + this.client = client; } @OverridingMethodsMustInvokeSuper @@ -52,6 +52,7 @@ protected void setupEventRouting(EventRouting routing) { @Override protected void configure(SpineOrgInitProcess processManager) { - processManager.setClient(travisClient); + super.configure(processManager); + processManager.setClient(client); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java index 89f92ba1..94e07727 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatProcess.java @@ -71,9 +71,9 @@ Pair> on(@External BuildFailed e) { Pair> on(@External BuildRecovered e) { var change = e.getChange(); var build = change.getNewValue(); - var repository = e.getRepository(); - _info().log("A build for the repository `%s` recovered.", repository.getValue()); - return processBuildStateUpdate(build, repository); + var repo = e.getRepository(); + _info().log("A build for the repository `%s` recovered.", repo.getValue()); + return processBuildStateUpdate(build, repo); } private Pair> diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java index 59ca4afe..88bff3cd 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/IncomingEventsControllerTest.java @@ -76,12 +76,12 @@ void receiveAndDecode() { .setMessageId("129y418y4houfhiuehwr") .setData(ByteString.copyFromUtf8(chatEventJson())) .build(); - var pushNotification = PubsubPushRequest + var pushRequest = PubsubPushRequest .newBuilder() .setMessage(pubsubMessage) .setSubscription("projects/test-project/subscriptions/test-subscription") .vBuild(); - var request = POST("/chat/incoming/event", Json.toJson(pushNotification)) + var request = POST("/chat/incoming/event", Json.toJson(pushRequest)) .contentType(MediaType.APPLICATION_JSON); String actual = client.toBlocking() .retrieve(request); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java index a8eebb7b..96753796 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/PubsubPushRequestDeserializerTest.java @@ -50,7 +50,6 @@ final class PubsubPushRequestDeserializerTest { @Test @DisplayName("deserialize Pub/Sub message") void deserializePubsubMessage() throws JsonProcessingException, ParseException { - var pubsubMessage = PubsubMessage .newBuilder() .setMessageId("450292511223766") @@ -65,8 +64,8 @@ void deserializePubsubMessage() throws JsonProcessingException, ParseException { var mapper = mapperFactory.objectMapper(nullRef(), nullRef()); - var pushNotification = mapper.readValue(pushRequestJson(), PubsubPushRequest.class); - ProtoTruth.assertThat(pushNotification) + var pushRequest = mapper.readValue(pushRequestJson(), PubsubPushRequest.class); + ProtoTruth.assertThat(pushRequest) .isEqualTo(expectedResult); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java index 532343b1..9e79b271 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubContextAwareTest.java @@ -31,13 +31,13 @@ */ abstract class GitHubContextAwareTest extends ContextAwareTest { - private final InMemoryTravisClient travisClient = InMemoryTravisClient.strictClient(); + private final InMemoryTravisClient client = InMemoryTravisClient.strictClient(); @Override protected final BoundedContextBuilder contextBuilder() { return GitHubContext .newBuilder() - .setTravis(travisClient) + .setTravis(client) .build() .builder(); } @@ -47,13 +47,13 @@ protected final BoundedContextBuilder contextBuilder() { @Override protected final void closeContext() { super.closeContext(); - travisClient.reset(); + client.reset(); } /** * Returns configured for the {@link #context() context} Travis client. */ final InMemoryTravisClient travisClient() { - return travisClient; + return client; } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index b7a90a05..770142e9 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -94,12 +94,12 @@ final class RegisterRepo { private static final String orgName = "Multi Repo Org"; - private final SpaceId googleChatSpace = space("spaces/qqwp123ttQ"); - private final OrganizationId organization = organization("MultiRepoOrg"); - private final RepositoryId repository = repository("main-repo"); + private final SpaceId space = space("spaces/qqwp123ttQ"); + private final OrganizationId org = organization("MultiRepoOrg"); + private final RepositoryId repo = repository("main-repo"); - private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); - private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(organization)); + private final Url githubUrl = githubUrlFor(Slugs.forOrg(org)); + private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(org)); private final Url websiteUrl = Urls.create("https://multi-repo-organization.com"); private final OrgHeader orgHeader = OrgHeader @@ -108,7 +108,7 @@ final class RegisterRepo { .setTravisProfile(travisCiUrl) .setWebsite(websiteUrl) .setName(orgName) - .setSpace(googleChatSpace) + .setSpace(space) .vBuild(); private final RepoHeader repoHeader = RepoHeader @@ -116,14 +116,14 @@ final class RegisterRepo { .setGithubProfile(githubUrl) .setTravisProfile(travisCiUrl) .setName("Main Repo") - .setOrganization(organization) + .setOrganization(org) .vBuild(); @BeforeEach void registerOrg() { var registerOrganization = RegisterOrganization .newBuilder() - .setId(organization) + .setId(org) .setHeader(orgHeader) .vBuild(); context().receivesCommand(registerOrganization); @@ -134,16 +134,16 @@ void registerOrg() { void settingState() { var registerRepository = RegisterRepository .newBuilder() - .setId(repository) + .setId(repo) .setHeader(repoHeader) .vBuild(); context().receivesCommand(registerRepository); var expectedState = OrganizationRepositories .newBuilder() - .setOrganization(organization) - .addRepository(repository) + .setOrganization(org) + .addRepository(repo) .vBuild(); - context().assertState(organization, OrganizationRepositories.class) + context().assertState(org, OrganizationRepositories.class) .isEqualTo(expectedState); } @@ -152,17 +152,17 @@ void settingState() { void handleDuplicateRepos() { var registerRepository = RegisterRepository .newBuilder() - .setId(repository) + .setId(repo) .setHeader(repoHeader) .vBuild(); context().receivesCommand(registerRepository); context().receivesCommand(registerRepository); var expectedState = OrganizationRepositories .newBuilder() - .setOrganization(organization) - .addRepository(repository) + .setOrganization(org) + .addRepository(repo) .vBuild(); - context().assertState(organization, OrganizationRepositories.class) + context().assertState(org, OrganizationRepositories.class) .isEqualTo(expectedState); } @@ -171,16 +171,16 @@ void handleDuplicateRepos() { void ignoreRepoWithoutOrg() { var registerRepository = RegisterRepository .newBuilder() - .setId(repository) + .setId(repo) .setHeader(repoHeader.toBuilder() .clearOrganization()) .vBuild(); context().receivesCommand(registerRepository); var expectedState = OrganizationRepositories .newBuilder() - .setOrganization(organization) + .setOrganization(org) .vBuild(); - context().assertState(organization, OrganizationRepositories.class) + context().assertState(org, OrganizationRepositories.class) .isEqualTo(expectedState); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index a934b987..b893719a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -49,25 +49,25 @@ final class RepoBuildProcessTest extends GitHubContextAwareTest { private static final OrganizationId org = organization("SpineEventEngine"); - private static final RepositoryId repository = repository("SpineEventEngine/web"); - private static final SpaceId chatSpace = space("spaces/1245wrq"); + private static final RepositoryId repo = repository("SpineEventEngine/web"); + private static final SpaceId space = space("spaces/1245wrq"); @Test @DisplayName("throw `NoBuildsFound` rejection when Travis API cannot return builds for a repo") void throwNoBuildsFoundRejection() { - travisClient().setBuildsFor(Slugs.forRepo(repository), + travisClient().setBuildsFor(Slugs.forRepo(repo), RepoBranchBuildResponse.getDefaultInstance()); var checkRepoBuild = CheckRepositoryBuild .newBuilder() - .setRepository(repository) + .setRepository(repo) .setOrganization(org) - .setSpace(chatSpace) + .setSpace(space) .vBuild(); context().receivesCommand(checkRepoBuild); var noBuildsFound = RepositoryBuildRejections.NoBuildsFound .newBuilder() - .setRepository(repository) + .setRepository(repo) .vBuild(); context().assertEvent(noBuildsFound); } @@ -79,15 +79,15 @@ final class FailedBuild { private final io.spine.chatbot.travis.Build build = failedBuild(); private final RepoBranchBuildResponse branchBuild = branchBuildOf(build); - private final Build buildState = buildFrom(branchBuild, chatSpace); + private final Build buildState = buildFrom(branchBuild, space); @BeforeEach void sendCheckCommand() { - travisClient().setBuildsFor(Slugs.forRepo(repository), branchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repo), branchBuild); var checkRepoBuild = CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setSpace(chatSpace) + .setRepository(repo) + .setSpace(space) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoBuild); @@ -102,7 +102,7 @@ void producingEvent() { .vBuild(); var buildFailed = BuildFailed .newBuilder() - .setRepository(repository) + .setRepository(repo) .setChange(stateChange) .vBuild(); context().assertEvent(buildFailed); @@ -113,11 +113,11 @@ void producingEvent() { void settingState() { var expectedState = RepositoryBuild .newBuilder() - .setRepository(repository) + .setRepository(repo) .setBuild(buildState) .setCurrentState(buildState.getState()) .vBuild(); - context().assertState(repository, RepositoryBuild.class) + context().assertState(repo, RepositoryBuild.class) .isEqualTo(expectedState); } } @@ -130,27 +130,27 @@ final class RecoveredBuild { private final io.spine.chatbot.travis.Build previousBuild = failedBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); private final Build previousBuildState = buildFrom(previousBranchBuild, - chatSpace); + space); private final io.spine.chatbot.travis.Build newBuild = passingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); - private final Build newBuildState = buildFrom(newBranchBuild, chatSpace); + private final Build newBuildState = buildFrom(newBranchBuild, space); @BeforeEach void sendCheckCommands() { - travisClient().setBuildsFor(Slugs.forRepo(repository), previousBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repo), previousBranchBuild); var checkRepoFailure = CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setSpace(chatSpace) + .setRepository(repo) + .setSpace(space) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(Slugs.forRepo(repository), newBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repo), newBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setSpace(chatSpace) + .setRepository(repo) + .setSpace(space) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); @@ -166,7 +166,7 @@ void producingEvent() { .vBuild(); var buildFailed = BuildRecovered .newBuilder() - .setRepository(repository) + .setRepository(repo) .setChange(stateChange) .vBuild(); context().assertEvent(buildFailed); @@ -177,11 +177,11 @@ void producingEvent() { void settingState() { var expectedState = RepositoryBuild .newBuilder() - .setRepository(repository) + .setRepository(repo) .setBuild(newBuildState) .setCurrentState(newBuildState.getState()) .vBuild(); - context().assertState(repository, RepositoryBuild.class) + context().assertState(repo, RepositoryBuild.class) .isEqualTo(expectedState); } } @@ -196,36 +196,36 @@ final class StableBuild { private final io.spine.chatbot.travis.Build previousBuild = passingBuild(); private final RepoBranchBuildResponse previousBranchBuild = branchBuildOf(previousBuild); private final Build previousBuildState = buildFrom(previousBranchBuild, - chatSpace); + space); private final io.spine.chatbot.travis.Build newBuild = nextPassingBuild(); private final RepoBranchBuildResponse newBranchBuild = branchBuildOf(newBuild); - private final Build newBuildState = buildFrom(newBranchBuild, chatSpace); + private final Build newBuildState = buildFrom(newBranchBuild, space); @BeforeEach void sendCheckCommands() { - travisClient().setBuildsFor(Slugs.forRepo(repository), + travisClient().setBuildsFor(Slugs.forRepo(repo), branchBuildOf(initialFailedBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setSpace(chatSpace) + .setRepository(repo) + .setSpace(space) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(Slugs.forRepo(repository), previousBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repo), previousBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setSpace(chatSpace) + .setRepository(repo) + .setSpace(space) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); - travisClient().setBuildsFor(Slugs.forRepo(repository), newBranchBuild); + travisClient().setBuildsFor(Slugs.forRepo(repo), newBranchBuild); var checkRepoStable = CheckRepositoryBuild .newBuilder() - .setRepository(repository) - .setSpace(chatSpace) + .setRepository(repo) + .setSpace(space) .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoStable); @@ -241,7 +241,7 @@ void producingEvent() { .vBuild(); var buildSucceededAgain = BuildSucceededAgain .newBuilder() - .setRepository(repository) + .setRepository(repo) .setChange(stateChange) .vBuild(); context().assertEvent(buildSucceededAgain); @@ -252,11 +252,11 @@ void producingEvent() { void settingState() { var expectedState = RepositoryBuild .newBuilder() - .setRepository(repository) + .setRepository(repo) .setBuild(newBuildState) .setCurrentState(newBuildState.getState()) .vBuild(); - context().assertState(repository, RepositoryBuild.class) + context().assertState(repo, RepositoryBuild.class) .isEqualTo(expectedState); } } @@ -267,7 +267,7 @@ private static RepoBranchBuildResponse branchBuildOf(io.spine.chatbot.travis.Bui .setLastBuild(build) .setName("master") .setRepository(Repository.newBuilder() - .setSlug(repository.getValue())) + .setSlug(repo.getValue())) .buildPartial(); } @@ -364,7 +364,7 @@ private static Repository webRepository() { .newBuilder() .setId(1112) .setName("web") - .setSlug(repository.getValue()) + .setSlug(repo.getValue()) .buildPartial(); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 476e7385..d1b0ff1f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -32,10 +32,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; @DisplayName("`RepositoryAggregate` should") final class RepositoryAggregateTest extends GitHubContextAwareTest { @@ -48,25 +48,25 @@ final class Register { private static final String REPO_SLUG = ORG_SLUG + "/base"; private static final String REPO_NAME = "Spine Base"; - private final RepositoryId repository = repository(REPO_SLUG); - private final OrganizationId organization = organization(ORG_SLUG); + private final RepositoryId repo = repository(REPO_SLUG); + private final OrganizationId org = organization(ORG_SLUG); - private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); - private final Url travisCiUrl = travisUrlFor(Slugs.forRepo(repository)); - private final RepoHeader header = RepoHeader + private final Url githubProfile = githubUrlFor(Slugs.forOrg(org)); + private final Url travisProfile = travisUrlFor(Slugs.forRepo(repo)); + private final RepoHeader repoHeader = RepoHeader .newBuilder() - .setGithubProfile(githubUrl) - .setTravisProfile(travisCiUrl) + .setGithubProfile(githubProfile) + .setTravisProfile(travisProfile) .setName(REPO_NAME) - .setOrganization(organization) + .setOrganization(org) .vBuild(); @BeforeEach void registerRepository() { var registerRepository = RegisterRepository .newBuilder() - .setId(repository) - .setHeader(header) + .setId(repo) + .setHeader(repoHeader) .vBuild(); context().receivesCommand(registerRepository); } @@ -76,8 +76,8 @@ void registerRepository() { void producingEvent() { var repositoryRegistered = RepositoryRegistered .newBuilder() - .setRepository(repository) - .setHeader(header) + .setRepository(repo) + .setHeader(repoHeader) .vBuild(); context().assertEvent(repositoryRegistered); } @@ -87,10 +87,10 @@ void producingEvent() { void settingState() { var expectedState = Repository .newBuilder() - .setId(repository) - .setHeader(header) + .setId(repo) + .setHeader(repoHeader) .vBuild(); - context().assertState(repository, Repository.class) + context().assertState(repo, Repository.class) .isEqualTo(expectedState); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 70056d70..939472d2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -42,13 +42,13 @@ final class SpineOrgInitProcessTest extends GitHubContextAwareTest { final class Init { private final SpaceId space = space("spaces/qjwrp1441"); - private final Repository repository = Repository + private final Repository repo = Repository .newBuilder() .setId(123312L) .setName("time") .setSlug("SpineEventEngine/time") .vBuild(); - private final SpaceHeader header = SpaceHeader + private final SpaceHeader spaceHeader = SpaceHeader .newBuilder() .setThreaded(true) .setDisplayName("Test Space") @@ -58,13 +58,13 @@ final class Init { void registerSpace() { var repositoriesResponse = RepositoriesResponse .newBuilder() - .addRepositories(repository) + .addRepositories(repo) .vBuild(); travisClient().setRepositoriesFor(Slugs.forOrg(ORGANIZATION), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() .setSpace(space) - .setHeader(header) + .setHeader(spaceHeader) .vBuild(); context().receivesExternalEvent(spaceRegistered); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java index bac9d0f6..a9881d4f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatContextAwareTest.java @@ -31,13 +31,13 @@ */ abstract class GoogleChatContextAwareTest extends ContextAwareTest { - private final InMemoryGoogleChatClient googleChatClient = InMemoryGoogleChatClient.strictClient(); + private final InMemoryGoogleChatClient client = InMemoryGoogleChatClient.strictClient(); @Override protected final BoundedContextBuilder contextBuilder() { return GoogleChatContext .newBuilder() - .setClient(googleChatClient) + .setClient(client) .build() .builder(); } @@ -47,13 +47,13 @@ protected final BoundedContextBuilder contextBuilder() { @Override protected final void closeContext() { super.closeContext(); - googleChatClient.reset(); + client.reset(); } /** * Returns configured for the {@link #context() context} Google Chat client. */ final InMemoryGoogleChatClient googleChatClient() { - return googleChatClient; + return client; } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index bdbb0e05..e672dcdc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -43,8 +43,8 @@ @DisplayName("`IncomingEventsHandler` should") final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { - private static final SpaceId spaceId = space("spaces/fqeq325661a"); - private static final MessageId messageId = message("spaces/fqeq325661a/messages/422"); + private static final SpaceId space = space("spaces/fqeq325661a"); + private static final MessageId message = message("spaces/fqeq325661a/messages/422"); @Test @DisplayName("add bot to a space") @@ -54,7 +54,7 @@ void addBot() { var botAddedToSpace = BotAddedToSpace .newBuilder() .setEvent(chatEventReceived.getEvent()) - .setSpace(spaceId) + .setSpace(space) .vBuild(); // when context().receivesExternalEvent(chatEventReceived); @@ -70,7 +70,7 @@ void removeBot() { var botRemovedFromSpace = BotRemovedFromSpace .newBuilder() .setEvent(chatEventReceived.getEvent()) - .setSpace(spaceId) + .setSpace(space) .vBuild(); // when context().receivesExternalEvent(chatEventReceived); @@ -86,7 +86,7 @@ void receiveIncomingMessage() { var messageReceived = MessageReceived .newBuilder() .setEvent(chatEventReceived.getEvent()) - .setMessage(messageId) + .setMessage(message) .vBuild(); // when context().receivesExternalEvent(chatEventReceived); @@ -115,7 +115,7 @@ private static ChatEvent chatEventOfType(EventType type) { private static Message chatMessage() { return Message .newBuilder() - .setName(messageId.getValue()) + .setName(message.getValue()) .setSender(sender()) .setText("To be, or not to be, that is the question.") .vBuild(); @@ -131,7 +131,7 @@ private static User sender() { private static io.spine.chatbot.google.chat.incoming.Space chatSpace() { return io.spine.chatbot.google.chat.incoming.Space .newBuilder() - .setName(spaceId.getValue()) + .setName(space.getValue()) .setType(ROOM) .vBuild(); } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 69e0adf0..54b5d991 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -52,11 +52,10 @@ final class ThreadChatProcessTest { final class BuildIsFailed extends BuildStateChanged { @Override - EventMessage buildStateChangeEvent(RepositoryId repositoryId, - BuildStateChange stateChange) { + EventMessage buildStateChangeEvent(RepositoryId repo, BuildStateChange stateChange) { return BuildFailed .newBuilder() - .setRepository(repositoryId) + .setRepository(repo) .setChange(stateChange) .vBuild(); } @@ -68,11 +67,10 @@ EventMessage buildStateChangeEvent(RepositoryId repositoryId, final class BuildIsRecovered extends BuildStateChanged { @Override - EventMessage buildStateChangeEvent(RepositoryId repositoryId, - BuildStateChange stateChange) { + EventMessage buildStateChangeEvent(RepositoryId repo, BuildStateChange stateChange) { return BuildRecovered .newBuilder() - .setRepository(repositoryId) + .setRepository(repo) .setChange(stateChange) .vBuild(); } @@ -82,8 +80,8 @@ private abstract static class BuildStateChanged extends GoogleChatContextAwareTe private static final String buildNumber = "551"; - private final RepositoryId repository = repository("SpineEventEngine/money"); - private final ThreadId thread = thread(repository.getValue()); + private final RepositoryId repo = repository("SpineEventEngine/money"); + private final ThreadId thread = thread(repo.getValue()); private final SpaceId space = space("spaces/1241pjwqe"); private final BuildStateUpdate stateUpdate = BuildStateUpdate @@ -106,11 +104,11 @@ void receiveBuildStateChange() { .newBuilder() .setNewValue(newBuildState) .vBuild(); - var buildFailed = buildStateChangeEvent(repository, buildStateChange); + var buildFailed = buildStateChangeEvent(repo, buildStateChange); context().receivesExternalEvent(buildFailed); } - abstract EventMessage buildStateChangeEvent(RepositoryId repositoryId, + abstract EventMessage buildStateChangeEvent(RepositoryId repo, BuildStateChange stateChange); @Test diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java index bcda21f8..b12d3573 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/travis/InMemoryTravisClient.java @@ -76,10 +76,10 @@ public void setBuildsFor(Slug repository, RepoBranchBuildResponse branchBuild) { /** * Sets up a stub {@code repositories} response for a specified {@code owner}. */ - public void setRepositoriesFor(Slug owner, RepositoriesResponse repositories) { + public void setRepositoriesFor(Slug owner, RepositoriesResponse repos) { checkNotNull(owner); - checkNotNull(repositories); - responses.put(ReposQuery.forOwner(owner), repositories); + checkNotNull(repos); + responses.put(ReposQuery.forOwner(owner), repos); } /** From 04dbc32a6f9e76066661b2272a1e8e8bf6d976fe Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 15:07:27 +0300 Subject: [PATCH 465/492] Move GitHub-specific language to the `chatbot.github` package in order to make it reusable for both client and server. --- .../{server => }/github/SlugMixin.java | 3 +- .../chatbot/{server => }/github/Slugs.java | 6 +--- .../organization}/OrgHeaderAware.java | 3 +- .../github/organization/package-info.java} | 32 +++++-------------- .../io/spine/chatbot/github/package-info.java | 30 +++++++++++++++++ .../repository}/RepoHeaderAware.java | 3 +- .../repository}/RepositoryAware.java | 2 +- .../repository}/RepositoryAwareEvent.java | 2 +- .../repository/build}/BuildStateMixin.java | 5 +-- .../github/repository/build/package-info.java | 30 +++++++++++++++++ .../github/repository/package-info.java | 30 +++++++++++++++++ .../server/github/RepoBuildProcess.java | 2 ++ .../server/github/SpineOrgInitProcess.java | 1 + .../google/chat/ThreadChatRepository.java | 2 +- .../spine/chatbot/github/organization.proto | 2 +- .../github/organization_commands.proto | 2 +- .../chatbot/github/organization_events.proto | 2 +- .../spine/chatbot/github/repository.proto | 2 +- .../chatbot/github/repository_build.proto | 2 +- .../github/repository_build_events.proto | 2 +- .../github/repository_build_rejections.proto | 2 +- .../chatbot/github/repository_commands.proto | 2 +- .../chatbot/github/repository_events.proto | 2 +- .../proto/spine/chatbot/github/slug.proto | 2 +- .../{server => }/github/SlugMixinTest.java | 2 +- .../{server => }/github/SlugsTest.java | 2 +- .../io/spine/chatbot/net/MoreUrlsTest.java | 2 +- .../server/github/OrgReposProjectionTest.java | 1 + .../github/OrganizationAggregateTest.java | 5 +-- .../server/github/RepoBuildProcessTest.java | 1 + .../github/RepositoryAggregateTest.java | 1 + .../github/SpineOrgInitProcessTest.java | 1 + 32 files changed, 129 insertions(+), 57 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/github/SlugMixin.java (95%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/github/Slugs.java (92%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server/github => github/organization}/OrgHeaderAware.java (95%) rename google-chat-bot/src/{test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java => main/java/io/spine/chatbot/github/organization/package-info.java} (54%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/github/package-info.java rename google-chat-bot/src/main/java/io/spine/chatbot/{server/github => github/repository}/RepoHeaderAware.java (95%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server/github => github/repository}/RepositoryAware.java (97%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server/github => github/repository}/RepositoryAwareEvent.java (96%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server/github => github/repository/build}/BuildStateMixin.java (95%) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/package-info.java create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/github/repository/package-info.java rename google-chat-bot/src/test/java/io/spine/chatbot/{server => }/github/SlugMixinTest.java (97%) rename google-chat-bot/src/test/java/io/spine/chatbot/{server => }/github/SlugsTest.java (96%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java index f0ec90fe..3eb1b39b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SlugMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java @@ -18,10 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github; import io.spine.annotation.GeneratedMixin; -import io.spine.chatbot.github.SlugOrBuilder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java similarity index 92% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java index 2670e105..1dbf0360 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/Slugs.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java @@ -18,11 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; - -import io.spine.chatbot.github.OrganizationId; -import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.Slug; +package io.spine.chatbot.github; import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java index f00914b1..d01fc286 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/OrgHeaderAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java @@ -18,10 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github.organization; import io.spine.annotation.GeneratedMixin; -import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.google.chat.SpaceId; import io.spine.net.Url; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/package-info.java similarity index 54% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/organization/package-info.java index 3788e44c..69b88571 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/BuildStateMixinTest.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/package-info.java @@ -18,29 +18,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static io.spine.chatbot.server.github.BuildStateMixin.buildStateFrom; -import static io.spine.testing.Tests.nullRef; -import static org.junit.jupiter.api.Assertions.assertThrows; - -@DisplayName("`BuildStateMixin` should") -final class BuildStateMixinTest { +/** + * This package contains the GitHub organization-specific language. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.github.organization; - @SuppressWarnings("ResultOfMethodCallIgnored") - @Test - @DisplayName("not accept `null` build states") - void notAcceptNull() { - assertThrows(NullPointerException.class, () -> buildStateFrom(nullRef())); - } +import com.google.errorprone.annotations.CheckReturnValue; - @SuppressWarnings("ResultOfMethodCallIgnored") - @Test - @DisplayName("not accept unknown build states") - void notAcceptUnknownStates() { - assertThrows(IllegalArgumentException.class, () -> buildStateFrom("unknown")); - } -} +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/package-info.java new file mode 100644 index 00000000..682d9d72 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains the GitHub-specific language. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.github; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java index 54f44062..255ff3b1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoHeaderAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java @@ -18,11 +18,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github.repository; import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.github.OrganizationId; -import io.spine.chatbot.github.repository.RepoHeader; import io.spine.net.Url; /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepositoryAware.java similarity index 97% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepositoryAware.java index e65c286b..5febfc89 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepositoryAware.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github.repository; import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.github.RepositoryId; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepositoryAwareEvent.java similarity index 96% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepositoryAwareEvent.java index d4bcfd5e..f9d35bd7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepositoryAwareEvent.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepositoryAwareEvent.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github.repository; import com.google.errorprone.annotations.Immutable; import io.spine.annotation.GeneratedMixin; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java index 677f7043..330a5958 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java @@ -18,12 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github.repository.build; import io.spine.annotation.GeneratedMixin; -import io.spine.chatbot.github.repository.build.Build; -import io.spine.chatbot.github.repository.build.BuildOrBuilder; -import io.spine.chatbot.github.repository.build.BuildStateChange; import java.util.EnumSet; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/package-info.java new file mode 100644 index 00000000..9c6fb54a --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains the GitHub repository build-specific language. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.github.repository.build; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/package-info.java new file mode 100644 index 00000000..ada78377 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This package contains the GitHub repository-specific language. + */ +@CheckReturnValue +@ParametersAreNonnullByDefault +package io.spine.chatbot.github.repository; + +import com.google.errorprone.annotations.CheckReturnValue; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index c22515a0..62a4c5da 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -24,8 +24,10 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; +import io.spine.chatbot.github.repository.build.BuildStateMixin; import io.spine.chatbot.github.repository.build.Commit; import io.spine.chatbot.github.repository.build.RepositoryBuild; import io.spine.chatbot.github.repository.build.command.CheckRepositoryBuild; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 48b50148..cd770e6e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -25,6 +25,7 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 31f44481..86f35a5d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -21,12 +21,12 @@ package io.spine.chatbot.server.google.chat; import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper; +import io.spine.chatbot.github.repository.RepositoryAwareEvent; import io.spine.chatbot.github.repository.build.event.BuildFailed; import io.spine.chatbot.github.repository.build.event.BuildRecovered; import io.spine.chatbot.google.chat.GoogleChatClient; import io.spine.chatbot.google.chat.ThreadId; import io.spine.chatbot.google.chat.thread.ThreadChat; -import io.spine.chatbot.server.github.RepositoryAwareEvent; import io.spine.core.EventContext; import io.spine.server.procman.ProcessManagerRepository; import io.spine.server.route.EventRoute; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index 3cd7cf48..17fb3190 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -38,7 +38,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A GitHub organization. message Organization { option (entity) = {kind: AGGREGATE visibility: NONE}; - option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; + option (is).java_type = "OrgHeaderAware"; OrganizationId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto index 7d6ebba3..85ce7644 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_commands.proto @@ -35,7 +35,7 @@ import "spine/chatbot/github/organization.proto"; // A request to register an organization. message RegisterOrganization { - option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; + option (is).java_type = "io.spine.chatbot.github.organization.OrgHeaderAware"; OrganizationId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto index d15cacc3..4a62e9d5 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_events.proto @@ -35,7 +35,7 @@ import "spine/chatbot/github/organization.proto"; // An organization is registered. message OrganizationRegistered { - option (is).java_type = "io.spine.chatbot.server.github.OrgHeaderAware"; + option (is).java_type = "io.spine.chatbot.github.organization.OrgHeaderAware"; OrganizationId organization = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto index d262010e..119e5015 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository.proto @@ -36,7 +36,7 @@ import "spine/chatbot/github/identifiers.proto"; // A GitHub repository. message Repository { option (entity) = {kind: AGGREGATE visibility: NONE}; - option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; + option (is).java_type = "RepoHeaderAware"; RepositoryId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index ae6081be..d74a4f82 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -56,7 +56,7 @@ message RepositoryBuild { // A repository branch build. message Build { - option (is).java_type = "io.spine.chatbot.server.github.BuildStateMixin"; + option (is).java_type = "BuildStateMixin"; // Incremental number for a repository's builds. string number = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto index 7c818bbe..9a904d54 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_events.proto @@ -30,7 +30,7 @@ option java_outer_classname = "RepositoryBuildEventsProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; -option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; +option (every_is).java_type = "io.spine.chatbot.github.repository.RepositoryAwareEvent"; import "spine/chatbot/github/identifiers.proto"; import "spine/chatbot/github/repository_build.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto index 4bf53628..77a20878 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build_rejections.proto @@ -29,7 +29,7 @@ option java_package = "io.spine.chatbot.github.repository.build.rejection"; option java_multiple_files = false; option java_generate_equals_and_hash = true; -option (every_is).java_type = "io.spine.chatbot.server.github.RepositoryAwareEvent"; +option (every_is).java_type = "io.spine.chatbot.github.repository.RepositoryAwareEvent"; import "spine/chatbot/github/identifiers.proto"; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto index 48086b3c..7ee15b4e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_commands.proto @@ -35,7 +35,7 @@ import "spine/chatbot/github/repository.proto"; // A request to register a repository. message RegisterRepository { - option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; + option (is).java_type = "io.spine.chatbot.github.repository.RepoHeaderAware"; RepositoryId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto index e822326f..d0a012c7 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_events.proto @@ -35,7 +35,7 @@ import "spine/chatbot/github/repository.proto"; // A repository is registered. message RepositoryRegistered { - option (is).java_type = "io.spine.chatbot.server.github.RepoHeaderAware"; + option (is).java_type = "io.spine.chatbot.github.repository.RepoHeaderAware"; RepositoryId repository = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto index aab26d1b..9a2b2e1e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/slug.proto @@ -12,7 +12,7 @@ option java_generate_equals_and_hash = true; // A unique human-readable identifier. message Slug { - option (is).java_type = "io.spine.chatbot.server.github.SlugMixin"; + option (is).java_type = "SlugMixin"; // The slug value. // diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java similarity index 97% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java index 22fb9ac8..0e3747a4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugMixinTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugsTest.java similarity index 96% rename from google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java rename to google-chat-bot/src/test/java/io/spine/chatbot/github/SlugsTest.java index 24d56ce7..172ebf3d 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SlugsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugsTest.java @@ -18,7 +18,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; +package io.spine.chatbot.github; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java index 3a4f4df7..a4708985 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java @@ -21,7 +21,7 @@ package io.spine.chatbot.net; import io.spine.chatbot.github.Slug; -import io.spine.chatbot.server.github.Slugs; +import io.spine.chatbot.github.Slugs; import io.spine.net.Urls; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index 770142e9..d47aa9ca 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -22,6 +22,7 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.chatbot.github.organization.command.RegisterOrganization; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 0af07a1f..04a30424 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.github; import io.spine.chatbot.github.OrganizationId; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.command.RegisterOrganization; @@ -33,10 +34,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; +import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`OrganizationAggregate` should") final class OrganizationAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index b893719a..62647371 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -22,6 +22,7 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index d1b0ff1f..70c4e15e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -22,6 +22,7 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.repository.RepoHeader; import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 939472d2..ffc085b4 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.github; +import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.SpaceHeader; import io.spine.chatbot.google.chat.SpaceId; From 13a86ed0cf3aa39a34fe8c89b4f30564fdf182ec Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 15:13:07 +0300 Subject: [PATCH 466/492] Move Google Chat-specific language to appropriate packages in order to make it reusable for both client and server. --- .../chatbot/{server => }/google/chat/SpaceHeaderAware.java | 3 +-- .../chatbot/{server => }/google/chat/incoming/SpaceMixin.java | 4 +--- .../{server => }/google/chat/incoming/package-info.java | 2 +- .../chatbot/google/chat/incoming/incoming_chat_messages.proto | 3 +-- .../src/main/proto/spine/chatbot/google/chat/space.proto | 2 +- .../main/proto/spine/chatbot/google/chat/space_commands.proto | 2 +- .../main/proto/spine/chatbot/google/chat/space_events.proto | 2 +- 7 files changed, 7 insertions(+), 11 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/google/chat/SpaceHeaderAware.java (95%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/google/chat/incoming/SpaceMixin.java (90%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/google/chat/incoming/package-info.java (95%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/SpaceHeaderAware.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/SpaceHeaderAware.java index 2589ba08..c5a7a09c 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/SpaceHeaderAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/SpaceHeaderAware.java @@ -18,10 +18,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.google.chat; +package io.spine.chatbot.google.chat; import io.spine.annotation.GeneratedMixin; -import io.spine.chatbot.google.chat.SpaceHeader; /** * Common interface for messages aware of the {@link SpaceHeader}. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java similarity index 90% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java index 5ad27459..8f3eede2 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/SpaceMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java @@ -18,12 +18,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.google.chat.incoming; +package io.spine.chatbot.google.chat.incoming; import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.google.chat.SpaceId; -import io.spine.chatbot.google.chat.incoming.SpaceOrBuilder; -import io.spine.chatbot.google.chat.incoming.SpaceType; import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/package-info.java similarity index 95% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/package-info.java index a598a2c9..81c75e6a 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/incoming/package-info.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/package-info.java @@ -23,7 +23,7 @@ */ @CheckReturnValue @ParametersAreNonnullByDefault -package io.spine.chatbot.server.google.chat.incoming; +package io.spine.chatbot.google.chat.incoming; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto index 67ddc0ac..150721ff 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/incoming/incoming_chat_messages.proto @@ -142,8 +142,7 @@ message Thread { // reference declaration for more details. // message Space { - - option (is).java_type = "io.spine.chatbot.server.google.chat.incoming.SpaceMixin"; + option (is).java_type = "SpaceMixin"; // The resource name of the space, in the form "spaces/*". string name = 1 [(required) = true, (pattern).regex = "spaces/.+"]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto index 4cac3ffa..2f8d080b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space.proto @@ -35,7 +35,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A room or DM in Chat. message Space { option (entity) = {kind: AGGREGATE visibility: NONE}; - option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; + option (is).java_type = "SpaceHeaderAware"; SpaceId id = 1; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto index 7e561b93..c56b9224 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_commands.proto @@ -35,7 +35,7 @@ import "spine/chatbot/google/chat/space.proto"; // A request to register a Chat space. message RegisterSpace { - option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; + option (is).java_type = "io.spine.chatbot.google.chat.SpaceHeaderAware"; SpaceId id = 1 [(required) = true]; diff --git a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto index 8e4c1e47..e2d6421e 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/google/chat/space_events.proto @@ -35,7 +35,7 @@ import "spine/chatbot/google/chat/space.proto"; // A new Chat space registered. message SpaceRegistered { - option (is).java_type = "io.spine.chatbot.server.google.chat.SpaceHeaderAware"; + option (is).java_type = "io.spine.chatbot.google.chat.SpaceHeaderAware"; SpaceId space = 1 [(required) = true]; From e8f132ff41ca06ed98814c570e42da958bd350c6 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:14:58 +0300 Subject: [PATCH 467/492] Drop extra comment --- .../src/main/java/io/spine/chatbot/Application.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java index dabab6ef..5e7c2061 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/Application.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/Application.java @@ -62,9 +62,6 @@ public static void main(String[] args) { application.start(); } - /** - * Starts {@link Server} and runs the {@link Micronaut}. - */ private void start() { Server.withContexts(GitHubContext.newInstance(), GoogleChatContext.newInstance()) .start(); From 3d130c27fbfb278bc5135dfb13d97cd788cc3907 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:20:08 +0300 Subject: [PATCH 468/492] Use qualified name in the docs instead of FQN --- .../src/main/java/io/spine/chatbot/github/SlugMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java index 3eb1b39b..4c3ef629 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/SlugMixin.java @@ -26,7 +26,7 @@ import java.nio.charset.StandardCharsets; /** - * Augments {@link io.spine.chatbot.github.Slug Slug} with useful methods. + * Augments {@link Slug} with useful methods. */ @GeneratedMixin public interface SlugMixin extends SlugOrBuilder { From 447250330eb88878f618e0c7a1628ad235505a30 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:21:45 +0300 Subject: [PATCH 469/492] Wrap field names into {@code} --- .../io/spine/chatbot/github/organization/OrgHeaderAware.java | 2 +- .../io/spine/chatbot/github/repository/RepoHeaderAware.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java index d01fc286..f737b9fe 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/organization/OrgHeaderAware.java @@ -31,7 +31,7 @@ public interface OrgHeaderAware { /** - * Returns the organization header. + * Returns the organization {@code header}. * * @implNote This method is implemented in the deriving Protobuf messages. */ diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java index 255ff3b1..91acc055 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/RepoHeaderAware.java @@ -31,7 +31,7 @@ public interface RepoHeaderAware { /** - * Returns the repository header. + * Returns the repository {@code header}. * * @implNote This method is implemented in the deriving Protobuf messages. */ From 0492d62e0ca36e300fc4e0fcf7682b9b6fd19f0a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:23:45 +0300 Subject: [PATCH 470/492] Use {@linkplain} where appropriate. Fix misprints. --- .../chatbot/github/repository/build/BuildStateMixin.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java index 330a5958..d72f26c9 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java @@ -50,7 +50,7 @@ default boolean failed() { } /** - * Returns a capitalized label of the {@link Build.State build state}. + * Returns a capitalized label of the {@linkplain Build.State build state}. */ default String stateLabel() { var state = getState(); @@ -61,7 +61,7 @@ default String stateLabel() { } /** - * Creates an instance of the {@link Build.State build state} of out its + * Creates an instance of the {@linkplain Build.State build state} of out its * string representation. */ static Build.State buildStateFrom(String state) { @@ -77,7 +77,7 @@ static Build.State buildStateFrom(String state) { } /** - * Determines the {@link BuildStateChange state chage} of the build comparing to the + * Determines the {@linkplain BuildStateChange state change} of the build comparing to the * {@code previousState}. * * @see #stateChange(BuildStateMixin, BuildStateMixin) @@ -87,7 +87,7 @@ default BuildStateChange.Type stateChangeFrom(BuildStateMixin previousState) { } /** - * Determines the {@link BuildStateChange state chage} between build states. + * Determines the {@linkplain BuildStateChange state change} between build states. * *

          The status is considered: * From bb572824783838e3cead625662e4595158ccdaad Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:25:21 +0300 Subject: [PATCH 471/492] Wrap param names into {@code} --- .../java/io/spine/chatbot/google/chat/BuildStateUpdates.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java index 48b9aa3e..88a36ebb 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/BuildStateUpdates.java @@ -55,7 +55,8 @@ private BuildStateUpdates() { } /** - * Creates a new {@link Build} update message from the supplied state and thread. + * Creates a new {@link Build} update message from the supplied {@code build} + * and {@code thread}. * *

          If the thread has no name set, assumes that the update message should be * sent to a new thread. From 00a0465b1457e65976f9db25f0b88eafc46f25e4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:26:22 +0300 Subject: [PATCH 472/492] Add @see link to the respective docs --- .../main/java/io/spine/chatbot/google/chat/ChatWidgets.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java index bbb77221..b1ad8b19 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java @@ -38,6 +38,9 @@ /** * Provides building blocks to empower the rich messages sent to Google Chat. + * + * @see + * Google Chat Cards */ final class ChatWidgets { From aa1a1ffd2015350c16b3bf2838df099dfe67a4d5 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:28:25 +0300 Subject: [PATCH 473/492] Fix article usage --- .../main/java/io/spine/chatbot/google/chat/GoogleChatKey.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java index 0c092dc4..4f7fadef 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatKey.java @@ -46,7 +46,7 @@ private GoogleChatKey(String value) { } /** - * Creates the Google Chat service account key. + * Creates a new Google Chat service account key. */ static GoogleChatKey chatServiceAccountKey() { var value = checkNotEmptyOrBlank(retrieveSecret(CHAT_SERVICE_ACCOUNT)); From 4593b48647378cf94d3fbb38339ca326638f0914 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:49:58 +0300 Subject: [PATCH 474/492] Cleanup docs --- .../src/main/java/io/spine/chatbot/server/Server.java | 4 +++- .../main/java/io/spine/chatbot/server/ServerEnvironment.java | 2 +- .../io/spine/chatbot/server/github/RepoBuildProcess.java | 5 ++--- .../io/spine/chatbot/server/github/SpineOrgInitProcess.java | 4 +++- .../spine/chatbot/server/google/chat/GoogleChatContext.java | 4 +++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java index f1fd714a..0604d420 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/Server.java @@ -38,7 +38,9 @@ */ public final class Server implements Logging { - /** Name of the GRPC {@link io.spine.server.Server}. **/ + /** + * The name of the GRPC {@link io.spine.server.Server Server}. + */ private static final String SERVER_NAME = "ChatBotServer"; private final ImmutableSet contexts; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java index 050118dc..d4015503 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/ServerEnvironment.java @@ -31,7 +31,7 @@ import io.spine.server.transport.memory.InMemoryTransportFactory; /** - * Initializes the {@link io.spine.server.ServerEnvironment}. + * Initializes the {@link io.spine.server.ServerEnvironment ServerEnvironment}. * *

          Configures the {@link StorageFactory} depending on the current {@link Environment}. * Uses the Datastore storage factory for the production mode and in-memory storage for tests. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index 62a4c5da..ca787e13 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -64,7 +64,7 @@ * {@code passing} previously. *

        * - * Or, if the repository builds could not be retrieved, throws {@link NoBuildsFound} rejection. + * Or, if the repository builds cannot be retrieved, throws {@link NoBuildsFound} rejection. */ final class RepoBuildProcess extends ProcessManager @@ -76,8 +76,7 @@ final class RepoBuildProcess /** * Checks the repository build state and propagates the respective events. * - *

        If the repository build state could not be retrieved, - * throws {@link NoBuildsFound} rejection. + *

        If the repository build state cannot be retrieved, throws {@link NoBuildsFound} rejection. */ @Assign EitherOf3 handle(CheckRepositoryBuild c) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index cd770e6e..0114695d 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -62,7 +62,9 @@ final class SpineOrgInitProcess "base", "time", "core-java", "web", "gcloud-java", "bootstrap", "money", "jdbc-storage" ); - /** The initialization process ID. **/ + /** + * The initialization process ID. + */ static final OrganizationId ORGANIZATION = organization("SpineEventEngine"); @LazyInit diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index bd4e67d1..b5038a51 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -32,7 +32,9 @@ */ public final class GoogleChatContext implements ContextBuilderAware { - /** The name of the Google Chat Context. **/ + /** + * The name of the Google Chat Context. + */ static final String GOOGLE_CHAT_CONTEXT_NAME = "GoogleChat"; private final BoundedContextBuilder builder; From 6ffe9b110264f2e2e322ab6e08f3492eb9e969a1 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:51:53 +0300 Subject: [PATCH 475/492] User shorter name for the repository --- .../src/main/java/io/spine/chatbot/travis/BuildsQuery.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java index 175e58d7..4ffeeb7e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/BuildsQuery.java @@ -38,8 +38,8 @@ private BuildsQuery(String request) { * *

        Requests the latest build from the {@code master} branch. */ - public static BuildsQuery forRepo(Slug repository) { - var encodedSlug = repository.encodedValue(); + public static BuildsQuery forRepo(Slug repo) { + var encodedSlug = repo.encodedValue(); var request = "/repo/" + encodedSlug + "/branch/master?&include=build.commit,build.created_by"; From 702593059cc04f4596b19d97a4698f8e6941de92 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:55:58 +0300 Subject: [PATCH 476/492] Fix capitalization --- .../src/main/proto/spine/chatbot/github/organization_init.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto index dba36dc9..ca5d4f2b 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization_init.proto @@ -36,7 +36,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // The initialization process of the default watched organization resources. // // Ensures that watched resources organization and its repositories are initialized -// for a particular Chat Space. +// for a particular Chat space. // message OrganizationInit { option (entity) = {kind: PROCESS_MANAGER visibility: NONE}; From a93794bb3455fa5df89a6e184fe2ed58a5a6e013 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 17:57:26 +0300 Subject: [PATCH 477/492] Improve docs --- .../main/proto/spine/chatbot/github/repository_build.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto index d74a4f82..c69ffbb6 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/repository_build.proto @@ -44,7 +44,7 @@ message RepositoryBuild { RepositoryId repository = 1; - // The time of the last status check. + // The time of the last build status check. .google.protobuf.Timestamp when_last_checked = 2; // The current build. @@ -137,7 +137,7 @@ message Commit { string authored_by = 5; } -// Definition of a change in a `build_state` field. +// Definition of a change in a `build` field. message BuildStateChange { // The value of the field that's changing. From 15d86a6509b2487b0902e7b41eaa63712404ddb8 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 18:03:30 +0300 Subject: [PATCH 478/492] Drop usage of the shortcut javadocs notation --- .../src/test/java/io/spine/chatbot/CanFailFast.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java b/google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java index 07ae11ff..f2be68d2 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/CanFailFast.java @@ -31,7 +31,9 @@ */ public abstract class CanFailFast implements Logging { - /** Determines whether the client should fail if a particular response is not preconfigured. **/ + /** + * Determines whether the client should fail if a particular response is not preconfigured. + */ private final boolean failFast; /** From 8ba7ceb3b43b2f043378200700bd28888ffa9b6a Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 18:07:44 +0300 Subject: [PATCH 479/492] Move identifiers to common packages in order to use them both in client and server code --- .../chatbot/{server => }/github/GitHubIdentifiers.java | 7 ++----- .../java/io/spine/chatbot/google/chat/GoogleChat.java | 4 ++-- .../{server => }/google/chat/GoogleChatIdentifiers.java | 8 ++------ .../io/spine/chatbot/google/chat/incoming/SpaceMixin.java | 2 +- .../spine/chatbot/server/github/SpineOrgInitProcess.java | 4 ++-- .../io/spine/chatbot/server/google/chat/ChatEvents.java | 2 +- .../chatbot/server/google/chat/ThreadChatRepository.java | 2 +- .../chatbot/server/github/GitHubIdentifiersTest.java | 2 +- .../chatbot/server/github/OrgReposProjectionTest.java | 6 +++--- .../chatbot/server/github/OrganizationAggregateTest.java | 4 ++-- .../spine/chatbot/server/github/RepoBuildProcessTest.java | 6 +++--- .../chatbot/server/github/RepositoryAggregateTest.java | 4 ++-- .../chatbot/server/github/SpineOrgInitProcessTest.java | 2 +- .../server/google/chat/GoogleChatIdentifiersTest.java | 5 +++-- .../server/google/chat/IncomingEventsHandlerTest.java | 4 ++-- .../chatbot/server/google/chat/SpaceAggregateTest.java | 2 +- .../chatbot/server/google/chat/ThreadAggregateTest.java | 6 +++--- .../chatbot/server/google/chat/ThreadChatProcessTest.java | 8 ++++---- 18 files changed, 36 insertions(+), 42 deletions(-) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/github/GitHubIdentifiers.java (90%) rename google-chat-bot/src/main/java/io/spine/chatbot/{server => }/google/chat/GoogleChatIdentifiers.java (89%) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/GitHubIdentifiers.java similarity index 90% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifiers.java rename to google-chat-bot/src/main/java/io/spine/chatbot/github/GitHubIdentifiers.java index afcffe36..9eeeb5f8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubIdentifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/GitHubIdentifiers.java @@ -18,15 +18,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.github; - -import io.spine.chatbot.github.OrganizationId; -import io.spine.chatbot.github.RepositoryId; +package io.spine.chatbot.github; import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** - * A utility for working with {@link GitHubContext} identifiers. + * A utility for working with {@code GitHub} context identifiers. */ public final class GitHubIdentifiers { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java index 6ab13e8d..daa3ee76 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java @@ -30,8 +30,8 @@ import java.io.IOException; import static io.spine.chatbot.google.chat.BuildStateUpdates.buildStateMessage; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; import static io.spine.util.Exceptions.newIllegalStateException; diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiers.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatIdentifiers.java similarity index 89% rename from google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiers.java rename to google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatIdentifiers.java index 62c7ca6c..11c9a7f0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiers.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChatIdentifiers.java @@ -18,16 +18,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package io.spine.chatbot.server.google.chat; - -import io.spine.chatbot.google.chat.MessageId; -import io.spine.chatbot.google.chat.SpaceId; -import io.spine.chatbot.google.chat.ThreadId; +package io.spine.chatbot.google.chat; import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** - * A utility for working with {@link GoogleChatContext} identifiers. + * A utility for working with {@code Google Chat} context identifiers. */ public final class GoogleChatIdentifiers { diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java index 8f3eede2..947cc78f 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/incoming/SpaceMixin.java @@ -23,7 +23,7 @@ import io.spine.annotation.GeneratedMixin; import io.spine.chatbot.google.chat.SpaceId; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; /** * Provides utility helpers for the {@link io.spine.chatbot.google.chat.incoming.Space Space} type. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 0114695d..5979dbb7 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -43,10 +43,10 @@ import io.spine.server.procman.ProcessManager; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import static io.spine.chatbot.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.github.GitHubIdentifiers.repository; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; /** * Spine organization init process. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java index 114add06..023b684e 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ChatEvents.java @@ -26,7 +26,7 @@ import io.spine.chatbot.google.chat.incoming.event.MessageReceived; import static com.google.common.base.Preconditions.checkNotNull; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; /** * A utility for working with {@link ChatEvent}s. diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java index 86f35a5d..92bac486 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/ThreadChatRepository.java @@ -34,7 +34,7 @@ import java.util.Set; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.thread; import static io.spine.server.route.EventRoute.withId; /** diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java index 2c7db7ce..4c279195 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/GitHubIdentifiersTest.java @@ -20,7 +20,7 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.server.google.chat.GoogleChatIdentifiers; +import io.spine.chatbot.google.chat.GoogleChatIdentifiers; import io.spine.testing.UtilityClassTest; import org.junit.jupiter.api.DisplayName; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index d47aa9ca..e4042188 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -36,11 +36,11 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`OrgReposProjection` should") final class OrgReposProjectionTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index 04a30424..ed7689e7 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -34,10 +34,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`OrganizationAggregate` should") final class OrganizationAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index 62647371..eda5ab89 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -41,10 +41,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.server.github.RepoBuildProcess.buildFrom; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`RepoBuildProcess` should") final class RepoBuildProcessTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 70c4e15e..546dca4c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -33,10 +33,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.github.GitHubIdentifiers.repository; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; -import static io.spine.chatbot.server.github.GitHubIdentifiers.organization; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; @DisplayName("`RepositoryAggregate` should") final class RepositoryAggregateTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index ffc085b4..0610d449 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -32,8 +32,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.server.github.SpineOrgInitProcess.ORGANIZATION; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`SpineOrgInitProcess` should") final class SpineOrgInitProcessTest extends GitHubContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java index d0cf2e06..f7cebf95 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/GoogleChatIdentifiersTest.java @@ -20,6 +20,7 @@ package io.spine.chatbot.server.google.chat; +import io.spine.chatbot.google.chat.GoogleChatIdentifiers; import io.spine.chatbot.google.chat.MessageId; import io.spine.chatbot.google.chat.SpaceId; import io.spine.testing.UtilityClassTest; @@ -34,8 +35,8 @@ import java.util.stream.Stream; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java index e672dcdc..b4f18fee 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/IncomingEventsHandlerTest.java @@ -33,12 +33,12 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.google.chat.incoming.EventType.ADDED_TO_SPACE; import static io.spine.chatbot.google.chat.incoming.EventType.MESSAGE; import static io.spine.chatbot.google.chat.incoming.EventType.REMOVED_FROM_SPACE; import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`IncomingEventsHandler` should") final class IncomingEventsHandlerTest extends GoogleChatContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java index 51b26654..f19ba354 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/SpaceAggregateTest.java @@ -33,9 +33,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.google.chat.incoming.EventType.ADDED_TO_SPACE; import static io.spine.chatbot.google.chat.incoming.SpaceType.ROOM; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; @DisplayName("`SpaceAggregate` should") final class SpaceAggregateTest extends GoogleChatContextAwareTest { diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java index 25b8f79b..37a2359c 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadAggregateTest.java @@ -34,9 +34,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @DisplayName("`ThreadAggregate` should") diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java index 54b5d991..ae10c71f 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/google/chat/ThreadChatProcessTest.java @@ -37,10 +37,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import static io.spine.chatbot.server.github.GitHubIdentifiers.repository; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.message; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.space; -import static io.spine.chatbot.server.google.chat.GoogleChatIdentifiers.thread; +import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; +import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.thread; import static io.spine.chatbot.server.google.chat.ThreadResources.threadResource; @DisplayName("`ThreadChatProcess` should") From 2ac05e4e01ea2e409fef47e11f8984468666773f Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 19:42:26 +0300 Subject: [PATCH 480/492] Add missing test --- .../repository/build/BuildStateMixinTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java new file mode 100644 index 00000000..8578f6f4 --- /dev/null +++ b/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.github.repository.build; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static io.spine.chatbot.github.repository.build.BuildStateMixin.buildStateFrom; +import static io.spine.testing.Tests.nullRef; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@DisplayName("`BuildStateMixin` should") +final class BuildStateMixinTest { + + @Test + @DisplayName("not accept `null` build states") + void notAcceptNull() { + assertThrows(NullPointerException.class, () -> buildStateFrom(nullRef())); + } + + @Test + @DisplayName("not accept unknown build states") + void notAcceptUnknownStates() { + assertThrows(IllegalArgumentException.class, () -> buildStateFrom("unknown")); + } +} From 6efcf33b0fbea7fd5f1aef7e64c2230ea37b6259 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 22:04:03 +0300 Subject: [PATCH 481/492] Add non-null checks --- .../main/java/io/spine/chatbot/google/chat/ChatWidgets.java | 5 +++-- .../main/java/io/spine/chatbot/google/chat/GoogleChat.java | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java index b1ad8b19..ce9620cc 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/ChatWidgets.java @@ -35,6 +35,7 @@ import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** * Provides building blocks to empower the rich messages sent to Google Chat. @@ -55,7 +56,7 @@ private ChatWidgets() { * and {@code url} to open upon a click. */ static Button linkButton(String title, Url url) { - checkNotNull(title); + checkNotEmptyOrBlank(title); checkNotNull(url); var button = new TextButton().setText(title) .setOnClick(openLink(url)); @@ -92,7 +93,7 @@ static Section sectionWithWidget(WidgetMarkup widget) { * Card text formatting */ static WidgetMarkup textParagraph(String formattedText) { - checkNotNull(formattedText); + checkNotEmptyOrBlank(formattedText); return new WidgetMarkup().setTextParagraph(new TextParagraph().setText(formattedText)); } } diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java index daa3ee76..64687b55 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/google/chat/GoogleChat.java @@ -29,6 +29,7 @@ import java.io.IOException; +import static com.google.api.client.util.Preconditions.checkNotNull; import static io.spine.chatbot.google.chat.BuildStateUpdates.buildStateMessage; import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.message; import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.thread; @@ -45,11 +46,13 @@ final class GoogleChat implements GoogleChatClient, Logging { private final HangoutsChat chat; GoogleChat(HangoutsChat chat) { - this.chat = chat; + this.chat = checkNotNull(chat); } @Override public BuildStateUpdate sendBuildStateUpdate(Build build, ThreadResource thread) { + checkNotNull(build); + checkNotNull(thread); var repo = build.getRepository(); var trace = _trace(); trace.log("Building state update message for the repository `%s`.", repo); From 1cabba91d80f4f6d2b7d8f790507a00884d305a2 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 22:10:57 +0300 Subject: [PATCH 482/492] Simplify string2enum conversion --- .../github/repository/build/BuildStateMixin.java | 16 ++++------------ .../repository/build/BuildStateMixinTest.java | 13 +++++++++++++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java index d72f26c9..00cf8fad 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/repository/build/BuildStateMixin.java @@ -24,14 +24,13 @@ import java.util.EnumSet; -import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.chatbot.github.repository.build.Build.State.BS_UNKNOWN; import static io.spine.chatbot.github.repository.build.Build.State.PASSED; import static io.spine.chatbot.github.repository.build.BuildStateChange.Type.FAILED; import static io.spine.chatbot.github.repository.build.BuildStateChange.Type.RECOVERED; import static io.spine.chatbot.github.repository.build.BuildStateChange.Type.STABLE; -import static io.spine.util.Exceptions.newIllegalArgumentException; import static io.spine.util.Exceptions.newIllegalStateException; +import static io.spine.util.Preconditions2.checkNotEmptyOrBlank; /** * Augments {@link Build} with useful methods. @@ -62,18 +61,11 @@ default String stateLabel() { /** * Creates an instance of the {@linkplain Build.State build state} of out its - * string representation. + * string representation, ignoring the case. */ static Build.State buildStateFrom(String state) { - checkNotNull(state); - for (Build.State buildState : Build.State.values()) { - if (state.equalsIgnoreCase(buildState.name())) { - return buildState; - } - } - throw newIllegalArgumentException( - "Unable to create build state out of the supplied string value `%s`.", state - ); + checkNotEmptyOrBlank(state); + return Build.State.valueOf(state.toUpperCase()); } /** diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java index 8578f6f4..7aa6f35a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/github/repository/build/BuildStateMixinTest.java @@ -22,10 +22,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import static io.spine.chatbot.github.repository.build.BuildStateMixin.buildStateFrom; import static io.spine.testing.Tests.nullRef; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.EnumSource.Mode.EXCLUDE; @DisplayName("`BuildStateMixin` should") final class BuildStateMixinTest { @@ -41,4 +45,13 @@ void notAcceptNull() { void notAcceptUnknownStates() { assertThrows(IllegalArgumentException.class, () -> buildStateFrom("unknown")); } + + @DisplayName("accept valid `Build.State` value") + @ParameterizedTest + @EnumSource(mode = EXCLUDE, value = Build.State.class, names = {"BS_UNKNOWN", "UNRECOGNIZED"}) + void processValidValues(Build.State state) { + assertDoesNotThrow(() -> { + buildStateFrom(state.name()); + }); + } } From b28e3c191b569e0937fa97091a969892e0210360 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 22:12:54 +0300 Subject: [PATCH 483/492] Start potentially long data with an empty line --- .../main/java/io/spine/chatbot/IncomingEventsController.java | 2 +- .../src/main/java/io/spine/chatbot/client/Client.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java index c8facb42..705ac0c8 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/IncomingEventsController.java @@ -56,7 +56,7 @@ String on(@Body PubsubPushRequest pushRequest) { var message = pushRequest.getMessage(); var chatEventJson = message.getData() .toStringUtf8(); - _debug().log("Received a new chat event: %s", chatEventJson); + _debug().log("Received a new chat event:%n%s", chatEventJson); ChatEvent chatEvent = Json.fromJson(chatEventJson, ChatEvent.class); var actor = eventActor(chatEvent.getUser()); var chatEventReceived = ChatEventReceived diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java index c31670b6..8818a2f0 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/client/Client.java @@ -123,7 +123,7 @@ public void post(CommandMessage command) { try { latch.await(); } catch (InterruptedException e) { - newIllegalStateException(e, "Processing of command interrupted: %s.", command); + newIllegalStateException(e, "Processing of command interrupted:%n%s.", command); } subscriptions.forEach(this::cancelSubscription); } From 35e99e53fbf0a6358dc3c5b24d15d6456a60cd69 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Wed, 15 Jul 2020 22:17:05 +0300 Subject: [PATCH 484/492] Improve `Slugs` methods naming --- .../java/io/spine/chatbot/github/Slugs.java | 10 +++++----- .../server/github/RepoBuildProcess.java | 9 +++++---- .../server/github/SpineOrgInitProcess.java | 9 +++++---- .../io/spine/chatbot/github/SlugMixinTest.java | 2 +- .../io/spine/chatbot/net/MoreUrlsTest.java | 2 +- .../server/github/OrgReposProjectionTest.java | 10 +++++----- .../github/OrganizationAggregateTest.java | 6 +++--- .../server/github/RepoBuildProcessTest.java | 18 ++++++++---------- .../server/github/RepositoryAggregateTest.java | 7 ++++--- .../server/github/SpineOrgInitProcessTest.java | 4 ++-- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java b/google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java index 1dbf0360..8222cec1 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/github/Slugs.java @@ -37,23 +37,23 @@ private Slugs() { /** * Creates a new {@code Slug} for the {@code repository}. */ - public static Slug forRepo(RepositoryId repo) { + public static Slug repoSlug(RepositoryId repo) { checkNotNull(repo); - return create(repo.getValue()); + return newSlug(repo.getValue()); } /** * Creates a new {@code Slug} for the {@code organization}. */ - public static Slug forOrg(OrganizationId org) { + public static Slug orgSlug(OrganizationId org) { checkNotNull(org); - return create(org.getValue()); + return newSlug(org.getValue()); } /** * Creates a new {@code Slug} with the specified {@code value}. */ - public static Slug create(String value) { + public static Slug newSlug(String value) { checkNotEmptyOrBlank(value); return Slug.newBuilder() .setValue(value) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java index ca787e13..8645ecff 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/RepoBuildProcess.java @@ -24,7 +24,6 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.Time; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.BuildStateMixin; @@ -46,6 +45,8 @@ import io.spine.server.tuple.EitherOf3; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import static io.spine.chatbot.github.Slugs.newSlug; +import static io.spine.chatbot.github.Slugs.repoSlug; import static io.spine.chatbot.net.MoreUrls.travisBuildUrlFor; import static io.spine.protobuf.Messages.isDefault; import static io.spine.util.Exceptions.newIllegalStateException; @@ -83,7 +84,7 @@ EitherOf3 handle(CheckReposito throws NoBuildsFound { var repo = c.getRepository(); _info().log("Checking build status for the repository `%s`.", repo.getValue()); - var branchBuild = client.execute(BuildsQuery.forRepo(Slugs.forRepo(repo))); + var branchBuild = client.execute(BuildsQuery.forRepo(repoSlug(repo))); if (isDefault(branchBuild.getLastBuild())) { _warn().log("No builds found for the repository `%s`.", repo.getValue()); throw NoBuildsFound @@ -164,8 +165,8 @@ EitherOf3 handle(CheckReposito @VisibleForTesting static Build buildFrom(RepoBranchBuildResponse branchBuild, SpaceId space) { var branchBuildName = branchBuild.getName(); - var slug = Slugs.create(branchBuild.getRepository() - .getSlug()); + var slug = newSlug(branchBuild.getRepository() + .getSlug()); var build = branchBuild.getLastBuild(); return Build .newBuilder() diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java index 5979dbb7..0466824b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/SpineOrgInitProcess.java @@ -25,7 +25,6 @@ import com.google.errorprone.annotations.concurrent.LazyInit; import io.spine.base.CommandMessage; import io.spine.chatbot.github.OrganizationId; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.command.RegisterOrganization; import io.spine.chatbot.github.organization.init.OrganizationInit; @@ -45,6 +44,8 @@ import static io.spine.chatbot.github.GitHubIdentifiers.organization; import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.github.Slugs.newSlug; +import static io.spine.chatbot.github.Slugs.orgSlug; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @@ -87,7 +88,7 @@ Iterable on(@External SpaceRegistered e) { _info().log("Starting Spine organization initialization process in the space `%s`.", space); var commands = ImmutableSet.builder(); commands.add(registerOrgCommand(ORGANIZATION, space)); - client.execute(ReposQuery.forOwner(Slugs.forOrg(ORGANIZATION))) + client.execute(ReposQuery.forOwner(orgSlug(ORGANIZATION))) .getRepositoriesList() .stream() .filter(repository -> WATCHED_REPOS.contains(repository.getName())) @@ -99,7 +100,7 @@ Iterable on(@External SpaceRegistered e) { } private RegisterRepository registerRepoCommand(Repository repo, OrganizationId org) { - var slug = Slugs.create(repo.getSlug()); + var slug = newSlug(repo.getSlug()); _info().log("Registering `%s` repository.", slug.getValue()); var header = RepoHeader .newBuilder() @@ -116,7 +117,7 @@ private RegisterRepository registerRepoCommand(Repository repo, OrganizationId o } private RegisterOrganization registerOrgCommand(OrganizationId spineOrg, SpaceId space) { - var slug = Slugs.forOrg(spineOrg); + var slug = orgSlug(spineOrg); _info().log("Registering `%s` organization.", spineOrg.getValue()); var header = OrgHeader .newBuilder() diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java index 0e3747a4..f5140060 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/github/SlugMixinTest.java @@ -31,7 +31,7 @@ final class SlugMixinTest { @Test @DisplayName("encode slug value") void encodeSlugValue() { - var slug = Slugs.create("TestOrganization/test-repository"); + var slug = Slugs.newSlug("TestOrganization/test-repository"); assertEquals("TestOrganization%2Ftest-repository", slug.encodedValue()); } } diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java index a4708985..0b615e3e 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/net/MoreUrlsTest.java @@ -36,7 +36,7 @@ @DisplayName("`MoreUrls` should") final class MoreUrlsTest extends UtilityClassTest { - private static final Slug REPO_SLUG = Slugs.create("SpineEventEngine/chat-bot"); + private static final Slug REPO_SLUG = Slugs.newSlug("SpineEventEngine/chat-bot"); MoreUrlsTest() { super(MoreUrls.class); diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java index e4042188..4b5dc47a 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrgReposProjectionTest.java @@ -22,7 +22,6 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.OrganizationRepositories; import io.spine.chatbot.github.organization.command.RegisterOrganization; @@ -38,6 +37,7 @@ import static io.spine.chatbot.github.GitHubIdentifiers.organization; import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.github.Slugs.orgSlug; import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @@ -54,8 +54,8 @@ final class RegisterOrg { private final SpaceId googleChatSpace = space("spaces/qwdp123tt1"); private final OrganizationId organization = organization("OurOrg"); - private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); - private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(organization)); + private final Url githubUrl = githubUrlFor(orgSlug(organization)); + private final Url travisCiUrl = travisUrlFor(orgSlug(organization)); private final Url websiteUrl = Urls.create("https://our-organization.com"); private final OrgHeader header = OrgHeader @@ -99,8 +99,8 @@ final class RegisterRepo { private final OrganizationId org = organization("MultiRepoOrg"); private final RepositoryId repo = repository("main-repo"); - private final Url githubUrl = githubUrlFor(Slugs.forOrg(org)); - private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(org)); + private final Url githubUrl = githubUrlFor(orgSlug(org)); + private final Url travisCiUrl = travisUrlFor(orgSlug(org)); private final Url websiteUrl = Urls.create("https://multi-repo-organization.com"); private final OrgHeader orgHeader = OrgHeader diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java index ed7689e7..9910c7cc 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/OrganizationAggregateTest.java @@ -21,7 +21,6 @@ package io.spine.chatbot.server.github; import io.spine.chatbot.github.OrganizationId; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.OrgHeader; import io.spine.chatbot.github.organization.Organization; import io.spine.chatbot.github.organization.command.RegisterOrganization; @@ -35,6 +34,7 @@ import org.junit.jupiter.api.Test; import static io.spine.chatbot.github.GitHubIdentifiers.organization; +import static io.spine.chatbot.github.Slugs.orgSlug; import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @@ -51,8 +51,8 @@ final class Register { private final SpaceId googleChatSpace = space("spaces/qwdp123ttQ"); private final OrganizationId organization = organization("TestOrganization"); - private final Url githubUrl = githubUrlFor(Slugs.forOrg(organization)); - private final Url travisCiUrl = travisUrlFor(Slugs.forOrg(organization)); + private final Url githubUrl = githubUrlFor(orgSlug(organization)); + private final Url travisCiUrl = travisUrlFor(orgSlug(organization)); private final Url websiteUrl = Urls.create("https://test-organization.com"); private final OrgHeader header = OrgHeader diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java index eda5ab89..f8cffe66 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepoBuildProcessTest.java @@ -22,7 +22,6 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.repository.build.Build; import io.spine.chatbot.github.repository.build.BuildStateChange; import io.spine.chatbot.github.repository.build.RepositoryBuild; @@ -43,6 +42,7 @@ import static io.spine.chatbot.github.GitHubIdentifiers.organization; import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.github.Slugs.repoSlug; import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.server.github.RepoBuildProcess.buildFrom; @@ -56,8 +56,7 @@ final class RepoBuildProcessTest extends GitHubContextAwareTest { @Test @DisplayName("throw `NoBuildsFound` rejection when Travis API cannot return builds for a repo") void throwNoBuildsFoundRejection() { - travisClient().setBuildsFor(Slugs.forRepo(repo), - RepoBranchBuildResponse.getDefaultInstance()); + travisClient().setBuildsFor(repoSlug(repo), RepoBranchBuildResponse.getDefaultInstance()); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setRepository(repo) @@ -84,7 +83,7 @@ final class FailedBuild { @BeforeEach void sendCheckCommand() { - travisClient().setBuildsFor(Slugs.forRepo(repo), branchBuild); + travisClient().setBuildsFor(repoSlug(repo), branchBuild); var checkRepoBuild = CheckRepositoryBuild .newBuilder() .setRepository(repo) @@ -139,7 +138,7 @@ final class RecoveredBuild { @BeforeEach void sendCheckCommands() { - travisClient().setBuildsFor(Slugs.forRepo(repo), previousBranchBuild); + travisClient().setBuildsFor(repoSlug(repo), previousBranchBuild); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setRepository(repo) @@ -147,7 +146,7 @@ void sendCheckCommands() { .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(Slugs.forRepo(repo), newBranchBuild); + travisClient().setBuildsFor(repoSlug(repo), newBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setRepository(repo) @@ -205,8 +204,7 @@ final class StableBuild { @BeforeEach void sendCheckCommands() { - travisClient().setBuildsFor(Slugs.forRepo(repo), - branchBuildOf(initialFailedBuild)); + travisClient().setBuildsFor(repoSlug(repo), branchBuildOf(initialFailedBuild)); var checkRepoFailure = CheckRepositoryBuild .newBuilder() .setRepository(repo) @@ -214,7 +212,7 @@ void sendCheckCommands() { .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoFailure); - travisClient().setBuildsFor(Slugs.forRepo(repo), previousBranchBuild); + travisClient().setBuildsFor(repoSlug(repo), previousBranchBuild); var checkRepoRecovery = CheckRepositoryBuild .newBuilder() .setRepository(repo) @@ -222,7 +220,7 @@ void sendCheckCommands() { .setOrganization(org) .vBuild(); context().receivesCommand(checkRepoRecovery); - travisClient().setBuildsFor(Slugs.forRepo(repo), newBranchBuild); + travisClient().setBuildsFor(repoSlug(repo), newBranchBuild); var checkRepoStable = CheckRepositoryBuild .newBuilder() .setRepository(repo) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java index 546dca4c..6b0b7764 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/RepositoryAggregateTest.java @@ -22,7 +22,6 @@ import io.spine.chatbot.github.OrganizationId; import io.spine.chatbot.github.RepositoryId; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.repository.RepoHeader; import io.spine.chatbot.github.repository.Repository; import io.spine.chatbot.github.repository.command.RegisterRepository; @@ -35,6 +34,8 @@ import static io.spine.chatbot.github.GitHubIdentifiers.organization; import static io.spine.chatbot.github.GitHubIdentifiers.repository; +import static io.spine.chatbot.github.Slugs.orgSlug; +import static io.spine.chatbot.github.Slugs.repoSlug; import static io.spine.chatbot.net.MoreUrls.githubUrlFor; import static io.spine.chatbot.net.MoreUrls.travisUrlFor; @@ -52,8 +53,8 @@ final class Register { private final RepositoryId repo = repository(REPO_SLUG); private final OrganizationId org = organization(ORG_SLUG); - private final Url githubProfile = githubUrlFor(Slugs.forOrg(org)); - private final Url travisProfile = travisUrlFor(Slugs.forRepo(repo)); + private final Url githubProfile = githubUrlFor(orgSlug(org)); + private final Url travisProfile = travisUrlFor(repoSlug(repo)); private final RepoHeader repoHeader = RepoHeader .newBuilder() .setGithubProfile(githubProfile) diff --git a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java index 0610d449..d5b26584 100644 --- a/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java +++ b/google-chat-bot/src/test/java/io/spine/chatbot/server/github/SpineOrgInitProcessTest.java @@ -20,7 +20,6 @@ package io.spine.chatbot.server.github; -import io.spine.chatbot.github.Slugs; import io.spine.chatbot.github.organization.init.OrganizationInit; import io.spine.chatbot.google.chat.SpaceHeader; import io.spine.chatbot.google.chat.SpaceId; @@ -32,6 +31,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static io.spine.chatbot.github.Slugs.orgSlug; import static io.spine.chatbot.google.chat.GoogleChatIdentifiers.space; import static io.spine.chatbot.server.github.SpineOrgInitProcess.ORGANIZATION; @@ -61,7 +61,7 @@ void registerSpace() { .newBuilder() .addRepositories(repo) .vBuild(); - travisClient().setRepositoriesFor(Slugs.forOrg(ORGANIZATION), repositoriesResponse); + travisClient().setRepositoriesFor(orgSlug(ORGANIZATION), repositoriesResponse); var spaceRegistered = SpaceRegistered .newBuilder() .setSpace(space) From f9caa16f5dd14d192bdcd6d01156f420312d937e Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 12:04:28 +0300 Subject: [PATCH 485/492] Add ability to query org aggregate --- .../src/main/proto/spine/chatbot/github/organization.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto index 17fb3190..26877789 100644 --- a/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto +++ b/google-chat-bot/src/main/proto/spine/chatbot/github/organization.proto @@ -37,7 +37,7 @@ import "spine/chatbot/google/chat/identifiers.proto"; // A GitHub organization. message Organization { - option (entity) = {kind: AGGREGATE visibility: NONE}; + option (entity) = {kind: AGGREGATE visibility: QUERY}; option (is).java_type = "OrgHeaderAware"; OrganizationId id = 1; From 2c8c26cfb387a7abc3766d44e86f4b2913046ba3 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 12:48:20 +0300 Subject: [PATCH 486/492] Do not ignore *all* `build` folders. It may happen that we have `build` as a package name in Java, thus with such a wildcard ignore all the files in the package are also ignored automatically. --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1670b25a..2707e789 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,9 @@ Thumbs.db .DS_Store .gradle -build/ +/build/ +/buildSrc/build/ +/google-chat-bot/build/ target/ out/ .idea From 6d0e07a521333b9189b3cd9d3cab22b851b187de Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 14:05:31 +0300 Subject: [PATCH 487/492] Fix env variable name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc8beb48..6ccca2cc 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ docker run \ -e "GOOGLE_APPLICATION_CREDENTIALS=${CONTAINER_CREDENTIALS_PATH}" \ -e "GCP_PROJECT_ID=${GCP_PROJECT_ID}" \ -v "${LOCAL_CREDENTIALS_PATH}:${CONTAINER_CREDENTIALS_PATH}" \ - gcr.io/${gcpProject}/chat-bot-server + gcr.io/${GCP_PROJECT_ID}/chat-bot-server ``` The application will be available at `127.0.0.1:${LOCAL_PORT}` (e.g. `127.0.0.1:9090`). From 693dcb2c36ffb8136526c3c0c862a0c07931fea4 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 14:14:05 +0300 Subject: [PATCH 488/492] Fix local credentials path --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6ccca2cc..09893d31 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,8 @@ Then run the following script from the repository root folder: export APP_PORT=8080 export LOCAL_PORT=9090 export CONTAINER_CREDENTIALS_PATH="/tmp/keys/gcp-adc.json" -export LOCAL_CREDENTIALS_PATH="${PWD}./credentials/gcp-adc.json" -export GCP_PROJECT_ID="" +export LOCAL_CREDENTIALS_PATH="${PWD}/.credentials/gcp-adc.json" +export GCP_PROJECT_ID="spine-chat-bot" docker run \ --tty \ --rm \ From 2ba2fa727819adf3ff11bbeb1164b5a50fc221cb Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 14:38:39 +0300 Subject: [PATCH 489/492] Bring back `api` prefix of the Travis API base URL. The prefix was removed accidentally as part of the `api` package removal. --- .../java/io/spine/chatbot/travis/Travis.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java index b6af5409..4fe36729 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/travis/Travis.java @@ -20,6 +20,8 @@ package io.spine.chatbot.travis; +import io.spine.logging.Logging; + import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; @@ -27,17 +29,17 @@ import static com.google.api.client.util.Preconditions.checkNotNull; import static io.spine.chatbot.travis.JsonProtoBodyHandler.jsonBodyHandler; -import static java.lang.String.format; +import static io.spine.util.Exceptions.newIllegalStateException; /** * A client to the Travis CI REST API. * * @see Travis CI API */ -final class Travis implements TravisClient { +final class Travis implements TravisClient, Logging { private static final HttpClient CLIENT = HttpClient.newHttpClient(); - private static final String BASE_URL = "https://travis-ci.com"; + private static final String BASE_URL = "https://api.travis-ci.com"; private static final String API_HEADER = "Travis-API-Version"; private static final String API_VERSION = "3"; private static final String AUTH_HEADER = "Authorization"; @@ -60,13 +62,15 @@ public T execute(Query query) { private T execute(String request, Class responseType) { var apiRequest = apiRequest(request, apiToken); try { + _trace().log("Executing Travis API request `%s` for response `%s`.", + request, responseType.getSimpleName()); var result = CLIENT.send(apiRequest, jsonBodyHandler(responseType)); return result.body(); } catch (IOException | InterruptedException e) { - var message = format( - "Unable to query data for response of type '%s' using request '%s'.", - responseType, request); - throw new RuntimeException(message, e); + throw newIllegalStateException( + e, "Unable to query data for response of type '%s' using request '%s'.", + responseType, request + ); } } From 0c36b06698ce34f267baf125af2f301bb482e812 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 14:41:01 +0300 Subject: [PATCH 490/492] Enable `trace`-level logs --- google-chat-bot/src/main/resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-chat-bot/src/main/resources/log4j2.xml b/google-chat-bot/src/main/resources/log4j2.xml index c15315ac..9e22026e 100644 --- a/google-chat-bot/src/main/resources/log4j2.xml +++ b/google-chat-bot/src/main/resources/log4j2.xml @@ -25,7 +25,7 @@ - + From 2929602ce4b5de4b629b4935e571491b9f8ebf94 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 15:11:52 +0300 Subject: [PATCH 491/492] Add diagnostic event logger for both bounded contexts. --- .../chatbot/server/DiagnosticEventLogger.java | 117 ++++++++++++++++++ .../chatbot/server/github/GitHubContext.java | 4 +- .../server/google/chat/GoogleChatContext.java | 4 +- 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 google-chat-bot/src/main/java/io/spine/chatbot/server/DiagnosticEventLogger.java diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/DiagnosticEventLogger.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/DiagnosticEventLogger.java new file mode 100644 index 00000000..f660e9d6 --- /dev/null +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/DiagnosticEventLogger.java @@ -0,0 +1,117 @@ +/* + * Copyright 2020, TeamDev. All rights reserved. + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.chatbot.server; + +import io.spine.base.Identifier; +import io.spine.core.Subscribe; +import io.spine.logging.Logging; +import io.spine.server.event.AbstractEventSubscriber; +import io.spine.system.server.CannotDispatchDuplicateCommand; +import io.spine.system.server.CannotDispatchDuplicateEvent; +import io.spine.system.server.ConstraintViolated; +import io.spine.system.server.HandlerFailedUnexpectedly; +import io.spine.system.server.RoutingFailed; +import io.spine.validate.diags.ViolationText; + +import java.util.stream.Collectors; + +/** + * Logs internal diagnostic events to ease applications management. + */ +public final class DiagnosticEventLogger extends AbstractEventSubscriber implements Logging { + + /** + * Logs entity constraint violation rejection. + */ + @Subscribe + void on(ConstraintViolated e) { + var entity = e.getEntity(); + var violations = e.getViolationList() + .stream() + .map(ViolationText::of) + .map(ViolationText::toString) + .collect(Collectors.joining()); + _error().log( + "Entity `%s` with value `%s` validation constraints are violated. The violations are:%n%s", + entity.getTypeUrl(), Identifier.toString(entity.id()), violations + ); + } + + /** + * Logs duplicate command delivery rejection. + */ + @Subscribe + void on(CannotDispatchDuplicateCommand e) { + var command = e.getDuplicateCommand(); + var entity = e.getEntity(); + _warn().log( + "Duplicate delivery of the command `%s` with ID `%s` to the entity `%s` with ID `%s` prevented.", + command.getTypeUrl(), Identifier.toString(command.getId()), + entity.getTypeUrl(), Identifier.toString(entity.id()) + ); + } + + /** + * Logs duplicate event delivery rejection. + */ + @Subscribe + void on(CannotDispatchDuplicateEvent e) { + var event = e.getDuplicateEvent(); + var entity = e.getEntity(); + _warn().log( + "Duplicate delivery of the event `%s` with ID `%s` to the entity `%s` with ID `%s` prevented.", + event.getTypeUrl(), Identifier.toString(entity.getId()), + entity.getTypeUrl(), Identifier.toString(entity.id()) + ); + } + + /** + * Logs unexpected signal handler exception. + */ + @Subscribe + void on(HandlerFailedUnexpectedly e) { + var signal = e.getHandledSignal(); + var entity = e.getEntity(); + var error = e.getError(); + _error().log( + "Signal `%s` with ID `%s` handler of the entity `%s` with ID `%s` failed with error `%s`.%n%s", + signal.getTypeUrl(), Identifier.toString(signal.id()), + entity.getTypeUrl(), Identifier.toString(entity.id()), + error.getMessage(), error.getStacktrace() + ); + } + + /** + * Logs routing failures. + */ + @Subscribe + void on(RoutingFailed e) { + var entityType = e.getEntityType() + .getJavaClassName(); + var signal = e.getHandledSignal(); + var error = e.getError(); + _error().log( + "Signal `%s` with ID `%s` routing to the entity `%s` failed with the error `%s`.%n%s", + signal.getTypeUrl(), Identifier.toString(signal.id()), + entityType, error.getMessage(), error.getStacktrace() + ); + } +} diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java index 93127a8c..4dbbb951 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/github/GitHubContext.java @@ -21,6 +21,7 @@ package io.spine.chatbot.server.github; import io.spine.chatbot.server.ContextBuilderAware; +import io.spine.chatbot.server.DiagnosticEventLogger; import io.spine.chatbot.travis.TravisClient; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -58,7 +59,8 @@ private static BoundedContextBuilder configureBuilder(TravisClient client) { .add(RepositoryAggregate.class) .add(new OrgReposRepository()) .add(new SpineOrgInitRepository(client)) - .add(new RepoBuildRepository(client)); + .add(new RepoBuildRepository(client)) + .addEventDispatcher(new DiagnosticEventLogger()); } /** diff --git a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java index b5038a51..af96266b 100644 --- a/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java +++ b/google-chat-bot/src/main/java/io/spine/chatbot/server/google/chat/GoogleChatContext.java @@ -22,6 +22,7 @@ import io.spine.chatbot.google.chat.GoogleChatClient; import io.spine.chatbot.server.ContextBuilderAware; +import io.spine.chatbot.server.DiagnosticEventLogger; import io.spine.server.BoundedContext; import io.spine.server.BoundedContextBuilder; @@ -61,7 +62,8 @@ public BoundedContextBuilder builder() { .add(new SpaceRepository()) .add(new ThreadRepository()) .add(new ThreadChatRepository(client)) - .addEventDispatcher(new IncomingEventsHandler()); + .addEventDispatcher(new IncomingEventsHandler()) + .addEventDispatcher(new DiagnosticEventLogger()); } /** From e46dd3e1e4963b6597b1e25e722b44f3d8b6c068 Mon Sep 17 00:00:00 2001 From: Yuri Sergiichuk Date: Thu, 16 Jul 2020 20:27:11 +0300 Subject: [PATCH 492/492] Bump version to 1.0.0 --- version.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle.kts b/version.gradle.kts index 36920ab2..79c72ebb 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -22,4 +22,4 @@ * The version of the application. */ -val botVersion: String by extra("0.9.0") +val botVersion: String by extra("1.0.0")