diff --git a/README.md b/README.md
index 45203a79..a03106b9 100644
--- a/README.md
+++ b/README.md
@@ -167,6 +167,13 @@ docker compose up -d
| **Ko-fi** | One-time / Recurring | [Donate using Ko-fi](https://ko-fi.com/FortuneN) |
| **Liberapay** | Recurring | [Donate using Liberapay](https://liberapay.com/FortuneN) |
+## Recognition
+
+| Source | Description |
+|-----------|-------------|
+| [Keycloak Extensions](https://www.keycloak.org/extensions) | Official Keycloak extensions directory |
+| [Awesome Keycloak](https://github.com/thomasdarimont/awesome-keycloak) | Community-curated list of Keycloak resources |
+
## Credits
| Library | Description |
diff --git a/pom.xml b/pom.xml
index 8ef4d62b..8101f821 100644
--- a/pom.xml
+++ b/pom.xml
@@ -923,6 +923,11 @@
org.apache.commons.logging
kete.org.apache.commons.logging
+
+
+ org.apache.commons.compress
+ kete.org.apache.commons.compress
+
javassist
@@ -1069,6 +1074,11 @@
com.microsoft.aad
kete.com.microsoft.aad
+
+
+ com.sun.jna
+ kete.com.sun.jna
+
com.google.api.client
@@ -1078,6 +1088,16 @@
com.google.api.services
kete.com.google.api.services
+
+
+ com.google.api
+ kete.com.google.api
+
+
+
+ org.apache.http
+ kete.org.apache.http
+
com.google.cloud
@@ -1131,6 +1151,11 @@
io.grpc
kete.io.grpc
+
+
+ org.codehaus.mojo.animal_sniffer
+ kete.org.codehaus.mojo.animal_sniffer
+
com.google.auto.value
diff --git a/run-on-develop-push.ps1 b/run-on-develop-push.ps1
index a65e902a..7f97ba50 100644
--- a/run-on-develop-push.ps1
+++ b/run-on-develop-push.ps1
@@ -164,7 +164,7 @@ if ($testsPassed) {
}
}
$color = if ($coveragePercent -ge 80) { "brightgreen" } elseif ($coveragePercent -ge 60) { "green" } elseif ($coveragePercent -ge 40) { "yellow" } else { "red" }
- $badgeJson = @{ schemaVersion = 1; label = "coverage"; message = "$coveragePercent%"; color = $color } | ConvertTo-Json
+ $badgeJson = @{ schemaVersion = 1; label = "Coverage"; message = "$coveragePercent%"; color = $color } | ConvertTo-Json
Set-Content -Path "coverage-badge.json" -Value $badgeJson -Encoding UTF8
Write-TaskResult "Coverage: $coveragePercent% (badge updated)" $true
}
diff --git a/run-on-release-push.ps1 b/run-on-release-push.ps1
index 6fe3d944..40d8c6b7 100644
--- a/run-on-release-push.ps1
+++ b/run-on-release-push.ps1
@@ -199,7 +199,7 @@ if ($testsPassed) {
}
}
$color = if ($coveragePercent -ge 80) { "brightgreen" } elseif ($coveragePercent -ge 60) { "green" } elseif ($coveragePercent -ge 40) { "yellow" } else { "red" }
- $badgeJson = @{ schemaVersion = 1; label = "coverage"; message = "$coveragePercent%"; color = $color } | ConvertTo-Json
+ $badgeJson = @{ schemaVersion = 1; label = "Coverage"; message = "$coveragePercent%"; color = $color } | ConvertTo-Json
Set-Content -Path "coverage-badge.json" -Value $badgeJson -Encoding UTF8
Write-TaskResult "Coverage: $coveragePercent% (badge updated)" $true
}
@@ -373,13 +373,22 @@ if (-not (Test-PreviousStepsPassed)) {
$tagName = "$($script:Version)"
Write-Task "Creating Git tag $tagName..."
- git tag -a $tagName -m "Release $tagName" 2>&1 | Out-Null
+ $tagOutput = git tag -a $tagName -m "Release $tagName" 2>&1
$tagCreated = $LASTEXITCODE -eq 0
+ if (-not $tagCreated) {
+ Write-Host " Tag creation error: $tagOutput" -ForegroundColor Red
+ }
+
if ($tagCreated) {
Write-Task "Pushing tag to origin..."
- git push origin $tagName 2>&1 | Out-Null
+ $pushOutput = git push origin $tagName 2>&1
$tagPushed = $LASTEXITCODE -eq 0
+
+ if (-not $tagPushed) {
+ Write-Host " Tag push error: $pushOutput" -ForegroundColor Red
+ }
+
Write-TaskResult "Git tag $tagName" $tagPushed
$script:Results["5. Git Tag"] = $tagPushed
} else {
@@ -390,8 +399,13 @@ if (-not (Test-PreviousStepsPassed)) {
if ($script:Results["5. Git Tag"]) {
Write-Task "Creating GitHub Release..."
$releaseNotes = ""
- gh release create $tagName --title "$tagName" --notes $releaseNotes "target/$script:JarName" 2>&1 | Out-Null
+ $releaseOutput = gh release create $tagName --title "$tagName" --notes $releaseNotes "target/$script:JarName" 2>&1
$releaseCreated = $LASTEXITCODE -eq 0
+
+ if (-not $releaseCreated) {
+ Write-Host " Release creation error: $releaseOutput" -ForegroundColor Red
+ }
+
Write-TaskResult "GitHub Release $tagName" $releaseCreated
$script:Results["5. GitHub Release"] = $releaseCreated
} else {
diff --git a/src/main/java/io/github/fortunen/kete/destinations/gcpcloudtasks/GcpCloudTasksDestination.java b/src/main/java/io/github/fortunen/kete/destinations/gcpcloudtasks/GcpCloudTasksDestination.java
index 5352538c..d4c04eee 100644
--- a/src/main/java/io/github/fortunen/kete/destinations/gcpcloudtasks/GcpCloudTasksDestination.java
+++ b/src/main/java/io/github/fortunen/kete/destinations/gcpcloudtasks/GcpCloudTasksDestination.java
@@ -5,11 +5,11 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-
import java.util.concurrent.TimeUnit;
import com.google.cloud.tasks.v2.CloudTasksGrpc;
import com.google.cloud.tasks.v2.CreateTaskRequest;
+import com.google.cloud.tasks.v2.GetQueueRequest;
import com.google.cloud.tasks.v2.HttpMethod;
import com.google.cloud.tasks.v2.HttpRequest;
import com.google.cloud.tasks.v2.ListQueuesRequest;
@@ -23,7 +23,11 @@
import io.github.fortunen.kete.utils.TemplateUtils;
import io.github.fortunen.kete.utils.ValidationUtils;
import io.grpc.ManagedChannel;
+import io.grpc.Metadata;
+import io.grpc.Status;
+import io.grpc.StatusRuntimeException;
import io.grpc.auth.MoreCallCredentials;
+import io.grpc.stub.MetadataUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@@ -68,14 +72,32 @@ public void doInitialize() {
// verify connection
- var parent = "projects/" + config.getProject() + "/locations/" + config.getLocation();
+ var deadlinedStub = stub.withDeadlineAfter(timeout.toSeconds(), TimeUnit.SECONDS);
- var listRequest = ListQueuesRequest.newBuilder()
- .setParent(parent)
- .setPageSize(1)
- .build();
+ try {
+
+ if (isQueueTemplated) {
+ var parent = "projects/" + config.getProject() + "/locations/" + config.getLocation();
+ var listRequest = ListQueuesRequest.newBuilder().setParent(parent).setPageSize(1).build();
+ var metadata = new Metadata();
+ metadata.put(Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER), "parent=" + parent);
+ deadlinedStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)).listQueues(listRequest);
+ } else {
+ var queueName = parentPathPrefix + queue;
+ var getRequest = GetQueueRequest.newBuilder().setName(queueName).build();
+ var metadata = new Metadata();
+ metadata.put(Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER), "name=" + queueName);
+ deadlinedStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)).getQueue(getRequest);
+ }
- stub.withDeadlineAfter(timeout.toSeconds(), TimeUnit.SECONDS).listQueues(listRequest);
+ } catch (StatusRuntimeException exception) {
+
+ if (exception.getStatus().getCode() != Status.Code.PERMISSION_DENIED) {
+ throw exception;
+ }
+
+ // connected but no read permission, no problem
+ }
}
@Override
@@ -126,7 +148,9 @@ public void doSend(EventMessage message) {
.setParent(parentPath)
.build();
- stub.createTask(request);
+ var metadata = new Metadata();
+ metadata.put(Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER), "parent=" + parentPath);
+ stub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata)).createTask(request);
}
@Override
diff --git a/src/main/java/io/github/fortunen/kete/destinations/gcppubsub/GcpPubSubDestination.java b/src/main/java/io/github/fortunen/kete/destinations/gcppubsub/GcpPubSubDestination.java
index 42da38d2..da575ed9 100644
--- a/src/main/java/io/github/fortunen/kete/destinations/gcppubsub/GcpPubSubDestination.java
+++ b/src/main/java/io/github/fortunen/kete/destinations/gcppubsub/GcpPubSubDestination.java
@@ -8,7 +8,9 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import com.google.api.client.http.GenericUrl;
+import org.apache.http.HttpStatus;
+
+import com.google.api.client.http.HttpResponseException;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.pubsub.Pubsub;
import com.google.api.services.pubsub.model.PublishRequest;
@@ -67,10 +69,22 @@ public void doInitialize() {
// verify connection
- httpTransport
- .createRequestFactory()
- .buildGetRequest(new GenericUrl(config.getUrl()))
- .execute();
+ try {
+
+ if (isTopicTemplated) {
+ pubsub.projects().topics().list("projects/" + config.getProject()).setPageSize(1).execute();
+ } else {
+ pubsub.projects().topics().get(publishTopicPrefix + topic).execute();
+ }
+
+ } catch (HttpResponseException exception) {
+
+ if (exception.getStatusCode() != HttpStatus.SC_FORBIDDEN) {
+ throw exception;
+ }
+
+ // connected but no read permission, no problem
+ }
}
@Override
diff --git a/src/test/java/io/github/fortunen/kete/unittests/destinations/gcpcloudtasksdestination/sendTests.java b/src/test/java/io/github/fortunen/kete/unittests/destinations/gcpcloudtasksdestination/sendTests.java
index 88c36b0e..843c8cfc 100644
--- a/src/test/java/io/github/fortunen/kete/unittests/destinations/gcpcloudtasksdestination/sendTests.java
+++ b/src/test/java/io/github/fortunen/kete/unittests/destinations/gcpcloudtasksdestination/sendTests.java
@@ -2,8 +2,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.nio.charset.StandardCharsets;
import java.util.Set;
@@ -17,6 +19,7 @@
import com.google.cloud.tasks.v2.CreateTaskRequest;
import io.github.fortunen.kete.Constants;
+import io.grpc.ClientInterceptor;
import io.github.fortunen.kete.EventMessage;
import io.github.fortunen.kete.destinations.gcpcloudtasks.GcpCloudTasksDestination;
import io.github.fortunen.kete.destinations.gcpcloudtasks.GcpCloudTasksDestinationConfig;
@@ -42,6 +45,7 @@ public void shouldCreateTaskWithCorrectFields() {
// arrange
var stub = mock(CloudTasksGrpc.CloudTasksBlockingStub.class);
+ when(stub.withInterceptors(any(ClientInterceptor[].class))).thenReturn(stub);
destination.setConfig(mock(GcpCloudTasksDestinationConfig.class));
destination.setStub(stub);
destination.setQueue("my-queue");