Skip to content

Commit f5a55f9

Browse files
authored
Merge branch 'main' into flatten-generated-modules
2 parents 85205d4 + 460a1b2 commit f5a55f9

17 files changed

Lines changed: 411 additions & 181 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,13 @@ jobs:
321321
- name: validate generation configuration
322322
shell: bash
323323
run: |
324-
docker run \
325-
--rm \
324+
bash generation/run_generator_docker.sh "${library_generation_image_tag}" "${{ github.base_ref || 'main' }}" \
325+
-e GENERATOR_VERSION="${library_generation_image_tag}" \
326326
--quiet \
327327
-u "$(id -u):$(id -g)" \
328328
-v "$(pwd):${workspace_name}" \
329329
--entrypoint python \
330-
gcr.io/cloud-devrel-public-resources/java-library-generation:"${library_generation_image_tag}" \
330+
-- \
331331
/src/library_generation/cli/entry_point.py validate-generation-config
332332
env:
333333
library_generation_image_tag: 2.68.0

.github/workflows/generated_files_sync.yaml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@ jobs:
2727
- name: Generate root pom.xml file
2828
shell: bash
2929
run: |
30-
docker run \
31-
--rm \
30+
bash generation/run_generator_docker.sh "${library_generation_image_tag}" "${{ github.base_ref }}" \
3231
--quiet \
3332
-u "$(id -u):$(id -g)" \
3433
-v "$(pwd):/workspace" \
3534
--entrypoint python \
36-
gcr.io/cloud-devrel-public-resources/java-library-generation:"${library_generation_image_tag}" \
35+
-- \
3736
/src/library_generation/cli/generate_monorepo_root_pom.py \
3837
generate \
3938
--repository-path=/workspace
@@ -48,13 +47,12 @@ jobs:
4847
- name: Generate gapic-libraries-bom/pom.xml
4948
shell: bash
5049
run: |
51-
docker run \
52-
--rm \
50+
bash generation/run_generator_docker.sh "${library_generation_image_tag}" "${{ github.base_ref }}" \
5351
--quiet \
5452
-u "$(id -u):$(id -g)" \
5553
-v "$(pwd):/workspace" \
5654
--entrypoint python \
57-
gcr.io/cloud-devrel-public-resources/java-library-generation:"${library_generation_image_tag}" \
55+
-- \
5856
/src/library_generation/cli/generate_monorepo_gapic_bom.py \
5957
generate \
6058
--repository-path=/workspace \

.github/workflows/hermetic_library_generation.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ on:
2020
env:
2121
REPO_FULL_NAME: ${{ github.event.pull_request.head.repo.full_name }}
2222
GITHUB_REPOSITORY: ${{ github.repository }}
23+
# {x-version-update-start:gapic-generator-java:current}
24+
GENERATOR_VERSION: 2.71.0
25+
# {x-version-update-end}
2326
jobs:
2427
library_generation:
2528
runs-on: ubuntu-latest
@@ -44,4 +47,4 @@ jobs:
4447
head_ref: ${{ github.head_ref }}
4548
token: ${{ secrets.CLOUD_JAVA_BOT_GITHUB_TOKEN }}
4649
force_regenerate_all: ${{ github.event.pull_request.head.ref == 'generate-libraries-main' }}
47-
image_tag: 2.71.0 # {x-version-update:gapic-generator-java:current}
50+
image_tag: ${{ env.GENERATOR_VERSION }}

generation/run_generator_docker.sh

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/bin/bash
2+
# Copyright 2026 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
set -exo pipefail
17+
18+
REQUESTED_TAG="$1"
19+
TARGET_BRANCH="$2"
20+
shift 2
21+
22+
# Parse arguments using '--' as delimiter
23+
DOCKER_OPTS=()
24+
CONTAINER_CMD=()
25+
found_delimiter=false
26+
27+
for arg in "$@"; do
28+
if [ "$arg" == "--" ]; then
29+
found_delimiter=true
30+
continue
31+
fi
32+
if $found_delimiter; then
33+
CONTAINER_CMD+=("$arg")
34+
else
35+
DOCKER_OPTS+=("$arg")
36+
fi
37+
done
38+
39+
IMAGE_NAME="gcr.io/cloud-devrel-public-resources/java-library-generation"
40+
# Support both local git and GitHub Actions environment variables
41+
CURRENT_BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-$(git branch --show-current)}}"
42+
IMAGE_TAG="$REQUESTED_TAG"
43+
44+
# Fallback logic on Release PR branches
45+
if [[ "$CURRENT_BRANCH" =~ ^release-please-- ]]; then
46+
echo "Detected release PR branch: $CURRENT_BRANCH"
47+
if ! docker pull "${IMAGE_NAME}:${IMAGE_TAG}"; then
48+
echo "Image not found for version ${IMAGE_TAG}. Falling back to previous version from ${TARGET_BRANCH}."
49+
# Extract tag from target branch's versions.txt using explicit fetch
50+
git fetch origin "${TARGET_BRANCH}" --depth=1 || true
51+
PREVIOUS_TAG=$(git show FETCH_HEAD:versions.txt | grep "^gapic-generator-java:" | cut -d ':' -f 2 || true)
52+
if [ -n "$PREVIOUS_TAG" ]; then
53+
echo "Using previous image version: $PREVIOUS_TAG"
54+
IMAGE_TAG="$PREVIOUS_TAG"
55+
else
56+
echo "Failed to extract fallback tag. Proceeding with requested tag."
57+
fi
58+
fi
59+
fi
60+
61+
# Execute Docker run with proper ordering
62+
docker run --rm "${DOCKER_OPTS[@]}" "${IMAGE_NAME}:${IMAGE_TAG}" "${CONTAINER_CMD[@]}"

generation_config.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
gapic_generator_version: 2.70.0
21
googleapis_commitish: 62e4ecb2f4390728990514fea14aad0431881a52
32
libraries_bom_version: 26.79.0
43
is_monorepo: true
@@ -1978,7 +1977,6 @@ libraries:
19781977
issue_tracker: https://issuetracker.google.com/savedsearches/559755
19791978
GAPICs:
19801979
- proto_path: google/cloud/oslogin/v1
1981-
- proto_path: google/cloud/oslogin/v1beta
19821980
- api_shortname: parallelstore
19831981
name_pretty: Parallelstore API
19841982
product_documentation: https://cloud/parallelstore?hl=en

java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ public class BigQueryConnection extends BigQueryNoOpsConnection {
139139
Long listenerPoolSize;
140140
String partnerToken;
141141
DatabaseMetaData databaseMetaData;
142+
Boolean reqGoogleDriveScope;
142143

143144
BigQueryConnection(String url) throws IOException {
144145
this(url, DataSource.fromUrl(url));
@@ -171,9 +172,15 @@ public class BigQueryConnection extends BigQueryNoOpsConnection {
171172
this.overrideProperties.put(
172173
BigQueryJdbcUrlUtility.UNIVERSE_DOMAIN_OVERRIDE_PROPERTY_NAME, this.universeDomain);
173174
}
175+
176+
this.reqGoogleDriveScope =
177+
BigQueryJdbcUrlUtility.convertIntToBoolean(
178+
String.valueOf(ds.getRequestGoogleDriveScope()),
179+
BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME);
180+
174181
this.credentials =
175182
BigQueryJdbcOAuthUtility.getCredentials(
176-
authProperties, overrideProperties, this.connectionClassName);
183+
authProperties, overrideProperties, this.reqGoogleDriveScope, this.connectionClassName);
177184
String defaultDatasetString = ds.getDefaultDataset();
178185
if (defaultDatasetString == null || defaultDatasetString.trim().isEmpty()) {
179186
this.defaultDataset = null;

java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcOAuthUtility.java

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ final class BigQueryJdbcOAuthUtility {
8080
+ "Thank you for using JDBC Driver for Google BigQuery!\n"
8181
+ "You may now close the window.</body></html>";
8282

83+
static final String BIGQUERY_SCOPE = "https://www.googleapis.com/auth/bigquery";
84+
static final String DRIVE_READONLY_SCOPE = "https://www.googleapis.com/auth/drive.readonly";
85+
86+
static final List<String> DEFAULT_BIGQUERY_SCOPES = Arrays.asList(BIGQUERY_SCOPE);
87+
static final List<String> BIGQUERY_WITH_DRIVE_SCOPES =
88+
Arrays.asList(BIGQUERY_SCOPE, DRIVE_READONLY_SCOPE);
89+
8390
private static final int USER_AUTH_TIMEOUT_MS = 120000;
8491
private static final BigQueryJdbcCustomLogger LOG =
8592
new BigQueryJdbcCustomLogger(BigQueryJdbcOAuthUtility.class.getName());
@@ -117,6 +124,7 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
117124
throw new IllegalArgumentException(OAUTH_TYPE_ERROR_MESSAGE);
118125
}
119126
oauthProperties.put(BigQueryJdbcUrlUtility.OAUTH_TYPE_PROPERTY_NAME, String.valueOf(authType));
127+
120128
switch (authType) {
121129
case GOOGLE_SERVICE_ACCOUNT:
122130
// For using a Google Service Account (OAuth Type 0)
@@ -144,11 +152,6 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
144152
BigQueryJdbcUrlUtility.OAUTH_CLIENT_ID_PROPERTY_NAME, ds.getOAuthClientId());
145153
oauthProperties.put(
146154
BigQueryJdbcUrlUtility.OAUTH_CLIENT_SECRET_PROPERTY_NAME, ds.getOAuthClientSecret());
147-
int reqGoogleDriveScope = ds.getRequestGoogleDriveScope();
148-
oauthProperties.put(
149-
BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME,
150-
String.valueOf(reqGoogleDriveScope));
151-
LOG.fine("RequestGoogleDriveScope parsed.");
152155
break;
153156
case PRE_GENERATED_TOKEN:
154157
String refreshToken = ds.getOAuthRefreshToken();
@@ -239,7 +242,7 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
239242
BigQueryJdbcUrlUtility.OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME,
240243
ds.getOAuthSAImpersonationScopes() != null
241244
? ds.getOAuthSAImpersonationScopes()
242-
: BigQueryJdbcUrlUtility.DEFAULT_OAUTH_SA_IMPERSONATION_SCOPES_VALUE);
245+
: BIGQUERY_SCOPE);
243246
oauthProperties.put(
244247
BigQueryJdbcUrlUtility.OAUTH_SA_IMPERSONATION_TOKEN_LIFETIME_PROPERTY_NAME,
245248
ds.getOAuthSAImpersonationTokenLifetime() != null
@@ -258,6 +261,7 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
258261
static GoogleCredentials getCredentials(
259262
Map<String, String> authProperties,
260263
Map<String, String> overrideProperties,
264+
Boolean reqGoogleDriveScopeBool,
261265
String callerClassName) {
262266
LOG.finest("++enter++\t" + callerClassName);
263267

@@ -280,15 +284,19 @@ static GoogleCredentials getCredentials(
280284
break;
281285
case APPLICATION_DEFAULT_CREDENTIALS:
282286
// This auth method doesn't support service account impersonation
283-
return getApplicationDefaultCredentials(callerClassName);
287+
288+
credentials = getApplicationDefaultCredentials(callerClassName);
289+
break;
284290
case EXTERNAL_ACCOUNT_AUTH:
285291
// This auth method doesn't support service account impersonation
286-
return getExternalAccountAuthCredentials(authProperties, callerClassName);
292+
credentials = getExternalAccountAuthCredentials(authProperties, callerClassName);
293+
break;
287294
default:
288295
throw new IllegalStateException(OAUTH_TYPE_ERROR_MESSAGE);
289296
}
290297

291-
return getServiceAccountImpersonatedCredentials(credentials, authProperties);
298+
return getServiceAccountImpersonatedCredentials(
299+
credentials, reqGoogleDriveScopeBool, authProperties);
292300
}
293301

294302
private static boolean isFileExists(String filename) {
@@ -388,29 +396,10 @@ static UserAuthorizer getUserAuthorizer(
388396
String callerClassName)
389397
throws URISyntaxException {
390398
LOG.finest("++enter++\t" + callerClassName);
399+
391400
List<String> scopes = new ArrayList<>();
392401
scopes.add("https://www.googleapis.com/auth/bigquery");
393402

394-
// Add Google Drive scope conditionally
395-
if (authProperties.containsKey(
396-
BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME)) {
397-
try {
398-
int driveScopeValue =
399-
Integer.parseInt(
400-
authProperties.get(
401-
BigQueryJdbcUrlUtility.REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME));
402-
if (driveScopeValue == 1) {
403-
scopes.add("https://www.googleapis.com/auth/drive.readonly");
404-
LOG.fine("Added Google Drive read-only scope. Caller: " + callerClassName);
405-
}
406-
} catch (NumberFormatException e) {
407-
LOG.severe(
408-
"Invalid value for RequestGoogleDriveScope, defaulting to not request Drive scope."
409-
+ " Caller: "
410-
+ callerClassName);
411-
}
412-
}
413-
414403
List<String> responseTypes = new ArrayList<>();
415404
responseTypes.add("code");
416405

@@ -500,14 +489,18 @@ private static GoogleCredentials getPreGeneratedAccessTokenCredentials(
500489
builder.setUniverseDomain(
501490
overrideProperties.get(BigQueryJdbcUrlUtility.UNIVERSE_DOMAIN_OVERRIDE_PROPERTY_NAME));
502491
}
492+
503493
LOG.info("Connection established. Auth Method: Pre-generated Access Token.");
504-
return builder
505-
.setAccessToken(
506-
AccessToken.newBuilder()
507-
.setTokenValue(
508-
authProperties.get(BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_PROPERTY_NAME))
509-
.build())
510-
.build();
494+
GoogleCredentials credentials =
495+
builder
496+
.setAccessToken(
497+
AccessToken.newBuilder()
498+
.setTokenValue(
499+
authProperties.get(BigQueryJdbcUrlUtility.OAUTH_ACCESS_TOKEN_PROPERTY_NAME))
500+
.build())
501+
.build();
502+
503+
return credentials;
511504
}
512505

513506
static GoogleCredentials getPreGeneratedTokensCredentials(
@@ -552,6 +545,7 @@ static UserCredentials getPreGeneratedRefreshTokenCredentials(
552545
userCredentialsBuilder.setUniverseDomain(
553546
overrideProperties.get(BigQueryJdbcUrlUtility.UNIVERSE_DOMAIN_OVERRIDE_PROPERTY_NAME));
554547
}
548+
555549
LOG.info("Connection established. Auth Method: Pre-generated Refresh Token.");
556550
return userCredentialsBuilder.build();
557551
}
@@ -571,6 +565,7 @@ private static GoogleCredentials getApplicationDefaultCredentials(String callerC
571565
LOG.info(
572566
"Connection established. Auth Method: Application Default Credentials, Principal: %s.",
573567
principal);
568+
574569
return credentials;
575570
} catch (IOException exception) {
576571
// TODO throw exception
@@ -634,13 +629,19 @@ private static GoogleCredentials getExternalAccountAuthCredentials(
634629
// This function checks if connection string contains configuration for
635630
// credentials impersonation. If not, it returns regular credentials object.
636631
// If impersonated service account is provided, returns Credentials object
637-
// accomodating this information.
632+
// accommodating this information.
638633
private static GoogleCredentials getServiceAccountImpersonatedCredentials(
639-
GoogleCredentials credentials, Map<String, String> authProperties) {
634+
GoogleCredentials credentials,
635+
Boolean reqGoogleDriveScopeBool,
636+
Map<String, String> authProperties) {
640637

641638
String impersonationEmail =
642639
authProperties.get(BigQueryJdbcUrlUtility.OAUTH_SA_IMPERSONATION_EMAIL_PROPERTY_NAME);
643640
if (impersonationEmail == null || impersonationEmail.isEmpty()) {
641+
if (reqGoogleDriveScopeBool) {
642+
credentials = credentials.createScoped(BIGQUERY_WITH_DRIVE_SCOPES);
643+
LOG.fine("Added Google Drive read-only scope to GoogleCredentials.");
644+
}
644645
return credentials;
645646
}
646647

@@ -653,10 +654,18 @@ private static GoogleCredentials getServiceAccountImpersonatedCredentials(
653654

654655
// Scopes has a default value, so it should never be null
655656
List<String> impersonationScopes =
656-
Arrays.asList(
657-
authProperties
658-
.get(BigQueryJdbcUrlUtility.OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME)
659-
.split(","));
657+
new java.util.ArrayList<>(
658+
Arrays.asList(
659+
authProperties
660+
.get(BigQueryJdbcUrlUtility.OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME)
661+
.split(",")));
662+
663+
if (reqGoogleDriveScopeBool) {
664+
if (!impersonationScopes.contains(DRIVE_READONLY_SCOPE)) {
665+
impersonationScopes.add(DRIVE_READONLY_SCOPE);
666+
LOG.fine("Added Google Drive read-only scope to impersonation scopes.");
667+
}
668+
}
660669

661670
// Token lifetime has a default value, so it should never be null
662671
String impersonationLifetime =

java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcUrlUtility.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ protected boolean removeEldestEntry(Map.Entry<String, Map<String, String>> eldes
7070
static final String HTAPI_ACTIVATION_RATIO_PROPERTY_NAME = "HighThroughputActivationRatio";
7171
static final String KMS_KEY_NAME_PROPERTY_NAME = "KMSKeyName";
7272
static final String QUERY_PROPERTIES_NAME = "QueryProperties";
73-
static final int DEFAULT_HTAPI_ACTIVATION_RATIO_VALUE =
74-
2; // TODO: to adjust this value before private preview based on performance testing.
73+
static final int DEFAULT_HTAPI_ACTIVATION_RATIO_VALUE = 2;
7574
static final String HTAPI_MIN_TABLE_SIZE_PROPERTY_NAME = "HighThroughputMinTableSize";
7675
static final int DEFAULT_HTAPI_MIN_TABLE_SIZE_VALUE = 100;
7776
static final int DEFAULT_OAUTH_TYPE_VALUE = -1;
@@ -86,8 +85,6 @@ protected boolean removeEldestEntry(Map.Entry<String, Map<String, String>> eldes
8685
static final String DEFAULT_OAUTH_SA_IMPERSONATION_CHAIN_VALUE = null;
8786
static final String OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME =
8887
"ServiceAccountImpersonationScopes";
89-
static final String DEFAULT_OAUTH_SA_IMPERSONATION_SCOPES_VALUE =
90-
"https://www.googleapis.com/auth/bigquery";
9188
static final String OAUTH_SA_IMPERSONATION_TOKEN_LIFETIME_PROPERTY_NAME =
9289
"ServiceAccountImpersonationTokenLifetime";
9390
static final String DEFAULT_OAUTH_SA_IMPERSONATION_TOKEN_LIFETIME_VALUE = "3600";

0 commit comments

Comments
 (0)