Skip to content

S226 local dev fix#97

Merged
jlorper merged 28 commits into
mainfrom
s226-local-dev-fix
May 28, 2026
Merged

S226 local dev fix#97
jlorper merged 28 commits into
mainfrom
s226-local-dev-fix

Conversation

@jlorper

@jlorper jlorper commented May 27, 2026

Copy link
Copy Markdown
Member

Fixes

Attempt to fix local dev datastore after Google bom update to 26.83.0 that introduced some changes to the datastore that broken local dev (that get's injected from worklyytics' main project)

Change implications

  • breaking change to API? no
  • changes dependencies? no

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, reopen this pull request to trigger a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to restore correct local-development behavior when using the Datastore emulator after a Google Cloud Java BOM update, by avoiding DatastoreOptions.toBuilder() (which can drop the emulator host) and instead rebuilding options via DatastoreOptions.newBuilder() while explicitly preserving host.

Changes:

  • Replaced DatastoreOptions.toBuilder() / getDefaultInstance().toBuilder() usage with explicit newBuilder() copies that retain host.
  • Removed a couple of “round-trip rebuilds” of DatastoreOptions and passed options/services through directly.
  • Bumped the fork version and documented the change (plus added internal agent docs).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
java/src/main/java/com/google/appengine/tools/mapreduce/ShardedJobAbstractSettings.java Rebuilds DatastoreOptions from default instance via newBuilder() while preserving host.
java/src/main/java/com/google/appengine/tools/mapreduce/MapReduceJob.java Updates multiple stage-specific Datastore construction sites to avoid toBuilder() and preserve host.
java/src/main/java/com/google/appengine/tools/mapreduce/impl/util/RequestUtils.java Rebuilds request-derived DatastoreOptions without toBuilder() to retain emulator host.
java/src/main/java/com/google/appengine/tools/mapreduce/impl/shardedjob/pipeline/FinalizeShardsInfos.java Stops rebuilding options via toBuilder() and uses datastoreOptions.getService().
java/src/main/java/com/google/appengine/tools/mapreduce/impl/shardedjob/pipeline/DeleteShardedJob.java Stops passing a toBuilder().build() copy of DatastoreOptions.
java/pom.xml Version bump to 0.3+worklytics.14.
java/changes.md Adds changelog entry describing the toBuilder() emulator-host issue and affected files.
.agents/plans/FIX-DATASTORE-TOBUILDER.md Internal plan documenting root cause and the intended replacement pattern.
.agents/CLAUDE.md Internal repository guidance for Claude Code usage and project architecture/testing notes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +244 to +251
DatastoreOptions defaultInstance = DatastoreOptions.getDefaultInstance();
DatastoreOptions.Builder b = DatastoreOptions.newBuilder()
.setProjectId(defaultInstance.getProjectId())
.setCredentials(defaultInstance.getCredentials())
.setTransportOptions(defaultInstance.getTransportOptions());
java.util.Optional.ofNullable(defaultInstance.getHost()).ifPresent(b::setHost);
java.util.Optional.ofNullable(settings.getNamespace()).ifPresent(b::setNamespace);
datastore = b.build().getService();
Comment on lines +353 to +358
DatastoreOptions defaultInstance = DatastoreOptions.getDefaultInstance();
DatastoreOptions.Builder b = DatastoreOptions.newBuilder()
.setProjectId(defaultInstance.getProjectId())
.setCredentials(defaultInstance.getCredentials())
.setTransportOptions(defaultInstance.getTransportOptions());
java.util.Optional.ofNullable(defaultInstance.getHost()).ifPresent(b::setHost);
Comment on lines +493 to +498
DatastoreOptions defaultInstance = DatastoreOptions.getDefaultInstance();
DatastoreOptions.Builder b = DatastoreOptions.newBuilder()
.setProjectId(defaultInstance.getProjectId())
.setCredentials(defaultInstance.getCredentials())
.setTransportOptions(defaultInstance.getTransportOptions());
java.util.Optional.ofNullable(defaultInstance.getHost()).ifPresent(b::setHost);
Comment on lines 23 to 25
protected Job<?> createShardsJob(int start, int end) {
return new DeleteShardsInfos(datastoreOptions.toBuilder().build(), getJobId(), start, end);
return new DeleteShardsInfos(datastoreOptions, getJobId(), start, end);
}
Comment on lines 33 to 35
public Value<Void> run() {
Datastore datastore = datastoreOptions.toBuilder().build().getService();
Datastore datastore = datastoreOptions.getService();

Comment thread java/changes.md
Comment on lines +5 to +6
(Google Cloud Java BOM ≥ 26.83.0). Replaced all `toBuilder()` / `getDefaultInstance().toBuilder()`
calls with explicit `DatastoreOptions.newBuilder()` copies that preserve the `host` field.
Comment on lines +70 to +76
DatastoreOptions defaultInstance = DatastoreOptions.getDefaultInstance();

DatastoreOptions.Builder builder = defaultInstance.toBuilder();
DatastoreOptions.Builder builder = DatastoreOptions.newBuilder()
.setProjectId(defaultInstance.getProjectId())
.setCredentials(defaultInstance.getCredentials())
.setTransportOptions(defaultInstance.getTransportOptions());
Optional.ofNullable(defaultInstance.getHost()).ifPresent(builder::setHost);
@Override
public Value<Void> run() {
Datastore datastore = datastoreOptions.toBuilder().build().getService();
Datastore datastore = EnvironmentUtils.datastoreBuilderFromDatastoreOptions(datastoreOptions).build().getService();
public Value<Void> run() {
Datastore datastore = datastoreOptions.toBuilder().build().getService();
// if coming from deserialization may lose transient properties that cause NPE
Datastore datastore = EnvironmentUtils.datastoreBuilderFromDatastoreOptions(datastoreOptions).build().getService();
jlorper and others added 6 commits May 28, 2026 13:11
…t order

Test was written for old order (enqueue tasks then commit Datastore). Current
implementation commits Datastore first, so when Datastore fails tasks are never
enqueued and nothing needs to be deleted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
finalize() is deprecated and marked for removal in modern Java. The override
only logged a warning for unclosed transactions — no actual resource cleanup.
Callers already have rollbackIfActive() for explicit cleanup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…local-dev-fix

# Conflicts:
#	java/pom.xml
#	java/src/test/java/com/google/appengine/tools/txn/PipelineBackendTransactionImplTest.java
Comment on lines +51 to +52
Set<PipelineTaskQueue.TaskReference> taskReferences = Collections
.singleton(PipelineTaskQueue.TaskReference.of("queue1", "task-ref"));
// Only used in tests
public AppEngineBackEnd(Options options, PipelineTaskQueue taskQueue, AppEngineServicesService appEngineServicesService) {
this(options.getDatastoreOptions().toBuilder().build().getService(), taskQueue, appEngineServicesService);
this(EnvironmentUtils.datastoreBuilderFromDatastoreOptions(options.getDatastoreOptions()).build().getService(), taskQueue, appEngineServicesService);
@jlorper jlorper enabled auto-merge May 28, 2026 16:32
@jlorper jlorper force-pushed the s226-local-dev-fix branch from 5c39231 to f6d8049 Compare May 28, 2026 17:28
@jlorper jlorper force-pushed the s226-local-dev-fix branch from f6d8049 to 27dd669 Compare May 28, 2026 17:32
@jlorper jlorper disabled auto-merge May 28, 2026 19:25
@jlorper jlorper merged commit 80745da into main May 28, 2026
15 of 27 checks passed
@jlorper jlorper deleted the s226-local-dev-fix branch May 28, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants