Skip to content

S219 : datastore databases - #94

Open
eschultink wants to merge 6 commits into
mainfrom
s219-datastore-databases
Open

eschultink wants to merge 6 commits into
mainfrom
s219-datastore-databases

Conversation

@eschultink

@eschultink eschultink commented Feb 27, 2026 •

Copy link
Copy Markdown
Member

Features

  • support pipeline data being stored in non-default Firestore database(s)
  • tests for pipeline data being stored in non-default Firestore database(s), namespace(s)

Change implications

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

@eschultink
eschultink requested review from aperez-worklytics and jlorper and a balanced review from Copilot February 27, 2026 22:55
@eschultink eschultink self-assigned this Feb 27, 2026

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

Adds support for running App Engine Pipelines against non-default Cloud Datastore / Firestore-in-Datastore-mode database IDs and namespaces, and verifies propagation/serialization via new unit tests.

Changes:

  • Introduces JobSetting.DatastoreDatabase / JobSetting.DatastoreNamespace and propagates these through JobRecord, PipelineModelObject key generation, and QueueSettings.
  • Serializes/deserializes datastore boundary settings on PipelineTask via task properties (dsDatabaseId, dsNamespace) and adds tests for round-tripping.
  • Adds Mockito MockMaker config and project agent/developer guidance.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker Adds a Mockito mock maker configuration for tests.
java/src/test/java/com/google/appengine/tools/pipeline/impl/tasks/PipelineTaskTest.java Tests task property round-trip including datastore database/namespace settings.
java/src/test/java/com/google/appengine/tools/pipeline/impl/model/PipelineModelObjectTest.java Updates key-generation test to include databaseId parameter.
java/src/test/java/com/google/appengine/tools/pipeline/impl/model/JobRecordTest.java Tests datastore database/namespace inheritance/override behavior in JobRecord.
java/src/test/java/com/google/appengine/tools/pipeline/JobSettingTest.java Adds validation tests for new datastore database/namespace job settings.
java/src/main/java/com/google/appengine/tools/pipeline/impl/tasks/PipelineTask.java Adds datastore database/namespace task properties and propagates them into task specs.
java/src/main/java/com/google/appengine/tools/pipeline/impl/model/PipelineModelObject.java Updates key generation to include databaseId (and propagate from parent/root keys).
java/src/main/java/com/google/appengine/tools/pipeline/impl/model/JobRecord.java Persists databaseId/namespace on job keys and inherits/overrides via JobSetting.
java/src/main/java/com/google/appengine/tools/pipeline/impl/QueueSettings.java Adds databaseId and namespace settings and merges them during inheritance.
java/src/main/java/com/google/appengine/tools/pipeline/JobSetting.java Adds DatastoreDatabase/DatastoreNamespace settings with validation.
AGENTS.md Documents architecture and rules around datastore boundary propagation.

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

Comment on lines +257 to +264
if (this.getQueueSettings().getDatabaseId() != null) {
spec.param("dsDatabaseId", this.getQueueSettings().getDatabaseId());
}

if (this.getQueueSettings().getNamespace() != null) {
spec.param("dsNamespace", this.getQueueSettings().getNamespace());
}

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

toTaskSpec() already adds all QueueSettings fields via this.toProperties().entrySet().forEach(...), and TaskProperty now includes dsDatabaseId/dsNamespace. The extra spec.param("dsDatabaseId"...) / spec.param("dsNamespace"...) block is redundant and can lead to empty-string values being forwarded as request params (since the guard is != null, not !isEmpty()), which then causes RequestUtils.buildDatastoreFromRequest() to call DatastoreOptions.Builder#setDatabaseId("") when the param is present. Consider removing the redundant block entirely, and/or normalizing databaseId/namespace so empty strings are treated as “unset” and not emitted as task params.

Suggested change
if (this.getQueueSettings().getDatabaseId() != null) {
spec.param("dsDatabaseId", this.getQueueSettings().getDatabaseId());
}
if (this.getQueueSettings().getNamespace() != null) {
spec.param("dsNamespace", this.getQueueSettings().getNamespace());
}

Copilot uses AI. Check for mistakes.
Comment thread java/src/main/java/com/google/appengine/tools/pipeline/JobSetting.java Outdated
Comment on lines +42 to +43
* delay in seconds to set when enqueueing the task (eg, should not execute
* until *at least* this much time has passed

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

The Javadoc for delayInSeconds opens a parenthesis (“(eg, …”) but doesn’t close it, which reads like a truncated sentence. Consider closing the parenthesis or rephrasing into a full sentence for clarity.

Suggested change
* delay in seconds to set when enqueueing the task (eg, should not execute
* until *at least* this much time has passed
* Delay in seconds to set when enqueueing the task (for example, the task should not execute
* until at least this much time has passed).

Copilot uses AI. Check for mistakes.
@eschultink
eschultink marked this pull request as ready for review March 9, 2026 20:30
eschultink and others added 2 commits May 5, 2026 10:49
Comment thread java/src/main/java/com/google/appengine/tools/pipeline/JobSetting.java Outdated
…del/PipelineModelObjectTest.java

Co-authored-by: aperez-worklytics <75276364+aperez-worklytics@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 25, 2026 21:55
…ing.java

Co-authored-by: aperez-worklytics <75276364+aperez-worklytics@users.noreply.github.com>
@eschultink
eschultink changed the base branch from rc-0.13 to main September 25, 2026 21:55

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.

Copilot review overview

🟡 Changes recommended

The tests do not compile, and datastore selection and propagation currently prevent reliable non-default database execution.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 4 High severity · 3 Medium severity

Open (7)

Comment on lines +492 to +493
databaseId = JobSetting.getSettingValue(JobSetting.DatastoreDatabase.class, settings)
.orElse(defaultDbId);
Comment on lines +524 to +526
String databaseId = JobSetting.getSettingValue(JobSetting.DatastoreDatabase.class, settings)
.orElse(null);
Key key = generateKey(projectId, databaseId, namespace, DATA_STORE_KIND);
Comment on lines +573 to +575
} else if (setting instanceof JobSetting.DatastoreNamespace ||
setting instanceof JobSetting.DatastoreDatabase) {
// ignore; applied in constructor, bc they are final
assertEquals("project", key.getProjectId());
assertEquals("ns", key.getNamespace());
assertEquals("Kind", key.getKind());
assertNull(key.getDatabase())
Comment on lines +227 to +228
if (StringUtils.isNotBlank(datastoreDatabase) && !"default".equalsIgnoreCase(datastoreDatabase)) {
if (!datastoreDatabase.matches("^[a-z][a-z0-9-]{1,61}[a-z0-9]$")) {
Comment on lines +245 to +247
if (datastoreNameSpace != null) {
if (!datastoreNameSpace.matches("^[0-9A-Za-z._-]{0,100}$")) {
throw new IllegalArgumentException("Invalid Datastore namespace: " + datastoreNameSpace);
Comment on lines +50 to +57
@Nullable
private String databaseId;

/**
* datastore namespace to propagate
*/
@Nullable
private String namespace;
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.

3 participants