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");