From 6f10ab453e6845fac9cea024a95c461039bb8ad1 Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Wed, 17 Jul 2024 12:06:57 -0500 Subject: [PATCH 1/2] Experimental cloud operations client Fixes #2059 --- .github/workflows/ci.yml | 37 +++++ .gitmodules | 3 + .../client/CloudOperationsClient.java | 37 +++++ .../client/CloudOperationsClientImpl.java | 36 +++++ .../client/CloudOperationsClientTest.java | 63 +++++++++ temporal-serviceclient/build.gradle | 9 ++ .../serviceclient/ChannelManager.java | 22 +++ .../serviceclient/CloudServiceStubs.java | 55 ++++++++ .../serviceclient/CloudServiceStubsImpl.java | 125 +++++++++++++++++ .../CloudServiceStubsOptions.java | 130 ++++++++++++++++++ temporal-serviceclient/src/main/protocloud | 1 + 11 files changed, 518 insertions(+) create mode 100644 temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClient.java create mode 100644 temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClientImpl.java create mode 100644 temporal-sdk/src/test/java/io/temporal/client/CloudOperationsClientTest.java create mode 100644 temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubs.java create mode 100644 temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsImpl.java create mode 100644 temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsOptions.java create mode 160000 temporal-serviceclient/src/main/protocloud diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caf85fb81..d70f4e6c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,6 +79,43 @@ jobs: with: report_paths: '**/build/test-results/test/TEST-*.xml' + unit_test_cloud: + name: Unit test with cloud + runs-on: ubuntu-latest + timeout-minutes: 30 + # Only supported in non-fork runs, since secrets are not available in forks + if: ${{ github.event.pull_request.head.repo.full_name == '' || github.event.pull_request.head.repo.full_name == 'temporalio/sdk-java' }} + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + ref: ${{ github.event.pull_request.head.sha }} + + - name: Set up Java + uses: actions/setup-java@v4 + with: + java-version: "11" + distribution: "temurin" + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Run cloud test + env: + USER: unittest + TEMPORAL_CLIENT_CLOUD_NAMESPACE: sdk-ci.a2dd6 + TEMPORAL_CLIENT_CLOUD_API_KEY: ${{ secrets.TEMPORAL_CLIENT_CLOUD_API_KEY }} + TEMPORAL_CLIENT_CLOUD_API_VERSION: 2024-05-13-00 + run: ./gradlew --no-daemon :temporal-sdk:test --tests '*CloudOperationsClientTest' + + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() # always run even if the previous step fails + with: + report_paths: '**/build/test-results/test/TEST-*.xml' + copyright: name: Copyright and code format runs-on: ubuntu-latest diff --git a/.gitmodules b/.gitmodules index 3222a3d13..74a657d3f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "temporal-serviceclient/src/main/proto"] path = temporal-serviceclient/src/main/proto url = https://github.com/temporalio/api.git +[submodule "temporal-serviceclient/src/main/protocloud"] + path = temporal-serviceclient/src/main/protocloud + url = https://github.com/temporalio/api-cloud.git diff --git a/temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClient.java b/temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClient.java new file mode 100644 index 000000000..fa46eb60c --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClient.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.client; + +import io.temporal.common.Experimental; +import io.temporal.serviceclient.CloudServiceStubs; + +/** Client to the Temporal Cloud operations service for performing cloud operations. */ +@Experimental +public interface CloudOperationsClient { + @Experimental + static CloudOperationsClient newInstance(CloudServiceStubs service) { + return new CloudOperationsClientImpl(service); + } + + /** Get the raw cloud service stubs. */ + @Experimental + CloudServiceStubs getCloudServiceStubs(); +} diff --git a/temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClientImpl.java b/temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClientImpl.java new file mode 100644 index 000000000..fea9a736c --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/client/CloudOperationsClientImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.client; + +import io.temporal.serviceclient.CloudServiceStubs; + +class CloudOperationsClientImpl implements CloudOperationsClient { + private final CloudServiceStubs cloudServiceStubs; + + CloudOperationsClientImpl(CloudServiceStubs cloudServiceStubs) { + this.cloudServiceStubs = cloudServiceStubs; + } + + @Override + public CloudServiceStubs getCloudServiceStubs() { + return cloudServiceStubs; + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/client/CloudOperationsClientTest.java b/temporal-sdk/src/test/java/io/temporal/client/CloudOperationsClientTest.java new file mode 100644 index 000000000..7cf394cb0 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/client/CloudOperationsClientTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.client; + +import io.temporal.api.cloud.cloudservice.v1.GetNamespaceRequest; +import io.temporal.api.cloud.cloudservice.v1.GetNamespaceResponse; +import io.temporal.serviceclient.CloudServiceStubs; +import io.temporal.serviceclient.CloudServiceStubsOptions; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +public class CloudOperationsClientTest { + private String namespace; + private String apiKey; + private String apiVersion; + + @Before + public void checkCloudEnvVars() { + namespace = System.getenv("TEMPORAL_CLIENT_CLOUD_NAMESPACE"); + apiKey = System.getenv("TEMPORAL_CLIENT_CLOUD_API_KEY"); + apiVersion = System.getenv("TEMPORAL_CLIENT_CLOUD_API_VERSION"); + Assume.assumeTrue( + "Cloud environment variables not present", namespace != null && apiKey != null); + } + + @Test + public void simpleCall() { + CloudOperationsClient client = + CloudOperationsClient.newInstance( + CloudServiceStubs.newServiceStubs( + CloudServiceStubsOptions.newBuilder() + .addApiKey(() -> apiKey) + .setVersion(apiVersion) + .build())); + // Do simple get namespace call + GetNamespaceResponse resp = + client + .getCloudServiceStubs() + .blockingStub() + .getNamespace(GetNamespaceRequest.newBuilder().setNamespace(namespace).build()); + Assert.assertEquals(namespace, resp.getNamespace().getNamespace()); + } +} diff --git a/temporal-serviceclient/build.gradle b/temporal-serviceclient/build.gradle index 8b51ba6ba..77ec23103 100644 --- a/temporal-serviceclient/build.gradle +++ b/temporal-serviceclient/build.gradle @@ -56,6 +56,15 @@ sourcesJar { .setDuplicatesStrategy(DuplicatesStrategy.EXCLUDE) } +// Putting protocloud as an additional proto source set +sourceSets { + main { + proto { + srcDir 'src/main/protocloud' + } + } +} + protobuf { // version/variables substitution is not supported in protobuf section. // protoc and protoc-gen-grpc-java versions are selected to be compatible diff --git a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/ChannelManager.java b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/ChannelManager.java index 38fa4e170..bca4113a3 100644 --- a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/ChannelManager.java +++ b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/ChannelManager.java @@ -75,6 +75,10 @@ final class ChannelManager { private static final Metadata.Key CLIENT_NAME_HEADER_KEY = Metadata.Key.of("client-name", Metadata.ASCII_STRING_MARSHALLER); + /** refers to the name of the gRPC header that contains the cloud service version */ + private static final Metadata.Key CLOUD_VERSION_HEADER_KEY = + Metadata.Key.of("temporal-cloud-api-version", Metadata.ASCII_STRING_MARSHALLER); + private static final String CLIENT_NAME_HEADER_VALUE = "temporal-java"; private final ServiceStubsOptions options; @@ -93,6 +97,18 @@ final class ChannelManager { public ChannelManager( ServiceStubsOptions options, List additionalHeadInterceptors) { + this(options, additionalHeadInterceptors, null); + } + + public ChannelManager( + ServiceStubsOptions options, + List additionalHeadInterceptors, + @Nullable Capabilities fixedServerCapabilities) { + // If fixed capabilities are present, set them on the future + if (fixedServerCapabilities != null) { + serverCapabilitiesFuture.complete(fixedServerCapabilities); + } + // Do not shutdown a channel passed to the constructor from outside this.channelNeedsShutdown = options.getChannel() == null; @@ -154,6 +170,12 @@ private Channel applyHeadStandardInterceptors(Channel channel) { headers.put(LIBRARY_VERSION_HEADER_KEY, Version.LIBRARY_VERSION); headers.put(SUPPORTED_SERVER_VERSIONS_HEADER_KEY, Version.SUPPORTED_SERVER_VERSIONS); headers.put(CLIENT_NAME_HEADER_KEY, CLIENT_NAME_HEADER_VALUE); + if (options instanceof CloudServiceStubsOptions) { + String version = ((CloudServiceStubsOptions) options).getVersion(); + if (version != null) { + headers.put(CLOUD_VERSION_HEADER_KEY, version); + } + } return ClientInterceptors.intercept( channel, diff --git a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubs.java b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubs.java new file mode 100644 index 000000000..77128ca42 --- /dev/null +++ b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubs.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.serviceclient; + +import static io.temporal.internal.WorkflowThreadMarker.enforceNonWorkflowThread; + +import io.temporal.api.cloud.cloudservice.v1.CloudServiceGrpc; +import io.temporal.internal.WorkflowThreadMarker; + +/** + * Initializes and holds gRPC blocking and future stubs. + * + *

WARNING: The cloud service is currently experimental. + */ +public interface CloudServiceStubs + extends ServiceStubs< + CloudServiceGrpc.CloudServiceBlockingStub, CloudServiceGrpc.CloudServiceFutureStub> { + String HEALTH_CHECK_SERVICE_NAME = "temporal.api.cloud.cloudservice.v1.CloudService"; + + /** Creates CloudService gRPC stubs pointed on to Temporal Cloud. */ + static CloudServiceStubs newCloudServiceStubs() { + return newServiceStubs(CloudServiceStubsOptions.getDefaultInstance()); + } + + /** + * Creates CloudService gRPC stubs
+ * This method creates stubs with lazy connectivity, connection is not performed during the + * creation time and happens on the first request. + * + * @param options stub options to use + */ + static CloudServiceStubs newServiceStubs(CloudServiceStubsOptions options) { + enforceNonWorkflowThread(); + return WorkflowThreadMarker.protectFromWorkflowThread( + new CloudServiceStubsImpl(options), CloudServiceStubs.class); + } +} diff --git a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsImpl.java b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsImpl.java new file mode 100644 index 000000000..1ff517691 --- /dev/null +++ b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.serviceclient; + +import io.grpc.ClientInterceptor; +import io.grpc.ManagedChannel; +import io.grpc.health.v1.HealthCheckResponse; +import io.temporal.api.cloud.cloudservice.v1.CloudServiceGrpc; +import io.temporal.api.workflowservice.v1.GetSystemInfoResponse; +import java.time.Duration; +import java.util.Collections; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class CloudServiceStubsImpl implements CloudServiceStubs { + private static final Logger log = LoggerFactory.getLogger(CloudServiceStubsImpl.class); + + private final ChannelManager channelManager; + + private final CloudServiceGrpc.CloudServiceBlockingStub blockingStub; + private final CloudServiceGrpc.CloudServiceFutureStub futureStub; + + /** + * Creates gRPC Channel and Stubs that connects to the {@link CloudServiceGrpc} according to the + * specified options. + */ + CloudServiceStubsImpl(CloudServiceStubsOptions options) { + ClientInterceptor deadlineInterceptor = + new GrpcDeadlineInterceptor(options.getRpcTimeout(), null, null); + + options = CloudServiceStubsOptions.newBuilder(options).validateAndBuildWithDefaults(); + + this.channelManager = + new ChannelManager( + options, + Collections.singletonList(deadlineInterceptor), + GetSystemInfoResponse.Capabilities.newBuilder() + .setInternalErrorDifferentiation(true) + .build()); + + log.info("Created CloudServiceStubs for channel: {}", channelManager.getRawChannel()); + + this.blockingStub = CloudServiceGrpc.newBlockingStub(channelManager.getInterceptedChannel()); + this.futureStub = CloudServiceGrpc.newFutureStub(channelManager.getInterceptedChannel()); + } + + @Override + public ManagedChannel getRawChannel() { + return channelManager.getRawChannel(); + } + + @Override + public CloudServiceGrpc.CloudServiceBlockingStub blockingStub() { + return blockingStub; + } + + @Override + public CloudServiceGrpc.CloudServiceFutureStub futureStub() { + return futureStub; + } + + @Override + public void shutdown() { + log.info("shutdown"); + channelManager.shutdown(); + } + + @Override + public void shutdownNow() { + log.info("shutdownNow"); + channelManager.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return channelManager.isShutdown(); + } + + @Override + public boolean isTerminated() { + return channelManager.isTerminated(); + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) { + return channelManager.awaitTermination(timeout, unit); + } + + @Override + public void connect(@Nullable Duration timeout) { + channelManager.connect(HEALTH_CHECK_SERVICE_NAME, timeout); + } + + @Override + public HealthCheckResponse healthCheck() { + // no need to pass timeout, timeout will be assigned by GrpcDeadlineInterceptor + return this.channelManager.healthCheck(HEALTH_CHECK_SERVICE_NAME, null); + } + + @Override + public Supplier getServerCapabilities() { + return this.channelManager.getServerCapabilities(); + } +} diff --git a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsOptions.java b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsOptions.java new file mode 100644 index 000000000..bc7a94af8 --- /dev/null +++ b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/CloudServiceStubsOptions.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.serviceclient; + +import io.grpc.ManagedChannel; +import java.util.Objects; + +/** + * Options for cloud service. + * + *

WARNING: The cloud service is currently experimental. + */ +public final class CloudServiceStubsOptions extends ServiceStubsOptions { + public static final String DEFAULT_CLOUD_TARGET = "saas-api.tmprl.cloud:443"; + + private static final CloudServiceStubsOptions DEFAULT_INSTANCE = + newBuilder().validateAndBuildWithDefaults(); + + /** Version header if any. */ + private final String version; + + public static Builder newBuilder() { + return new Builder(); + } + + public static Builder newBuilder(CloudServiceStubsOptions options) { + // We intentionally only accept our options and not the base class of + // options to ensure our defaults were originally applied at some point + // when the options class was first created. + return new Builder(options); + } + + public static CloudServiceStubsOptions getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private CloudServiceStubsOptions(ServiceStubsOptions serviceStubsOptions, String version) { + super(serviceStubsOptions); + this.version = version; + } + + /** + * @return Returns the version used for the version header if any. + */ + public String getVersion() { + return version; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + CloudServiceStubsOptions that = (CloudServiceStubsOptions) o; + return Objects.equals(version, that.version); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), version); + } + + /** Builder is the builder for ClientOptions. */ + public static class Builder extends ServiceStubsOptions.Builder { + private String version; + + private Builder() { + // Set defaults only in this constructor + setTarget(DEFAULT_CLOUD_TARGET); + setEnableHttps(true); + } + + private Builder(CloudServiceStubsOptions options) { + super(options); + this.version = options.version; + } + + /** Set a cloud operation service version. This sets the version header for each call. */ + public Builder setVersion(String version) { + this.version = version; + return this; + } + + /** Default is {@link #DEFAULT_CLOUD_TARGET}. See inherited method for more details. */ + @Override + public Builder setTarget(String target) { + return super.setTarget(target); + } + + @Override + public Builder setChannel(ManagedChannel channel) { + // Unset our defaults + setEnableHttps(false); + setTarget(null); + return super.setChannel(channel); + } + + /** + * Builds and returns a ClientOptions object. + * + * @return ClientOptions object with the specified params. + */ + public CloudServiceStubsOptions build() { + return new CloudServiceStubsOptions(super.build(), this.version); + } + + public CloudServiceStubsOptions validateAndBuildWithDefaults() { + ServiceStubsOptions serviceStubsOptions = super.validateAndBuildWithDefaults(); + return new CloudServiceStubsOptions(serviceStubsOptions, this.version); + } + } +} diff --git a/temporal-serviceclient/src/main/protocloud b/temporal-serviceclient/src/main/protocloud new file mode 160000 index 000000000..508379bad --- /dev/null +++ b/temporal-serviceclient/src/main/protocloud @@ -0,0 +1 @@ +Subproject commit 508379bad5b0ec0275dc5c0f4a8a884fbb6e7123 From f05ea425040a3351928d9efddb0db6c782ac3ae9 Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Thu, 18 Jul 2024 12:27:30 -0500 Subject: [PATCH 2/2] Move cloud CI conditional to specific step instead of entire job --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d70f4e6c4..da620fd5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,8 +83,6 @@ jobs: name: Unit test with cloud runs-on: ubuntu-latest timeout-minutes: 30 - # Only supported in non-fork runs, since secrets are not available in forks - if: ${{ github.event.pull_request.head.repo.full_name == '' || github.event.pull_request.head.repo.full_name == 'temporalio/sdk-java' }} steps: - name: Checkout repo uses: actions/checkout@v4 @@ -103,6 +101,10 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Run cloud test + # Only supported in non-fork runs, since secrets are not available in forks. We intentionally + # are only doing this check on the step instead of the job so we require job passing in CI + # even for those that can't run this step. + if: ${{ github.event.pull_request.head.repo.full_name == '' || github.event.pull_request.head.repo.full_name == 'temporalio/sdk-java' }} env: USER: unittest TEMPORAL_CLIENT_CLOUD_NAMESPACE: sdk-ci.a2dd6