Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GCS Enhancement #981

Merged
merged 12 commits into from
Sep 30, 2021
Merged

GCS Enhancement #981

merged 12 commits into from
Sep 30, 2021

Conversation

colerogers
Copy link
Contributor

Description

Enhancement to how customers use GCS Triggered Functions.

Code sample

onObjectArchived()
onObjectFinalized()
onObjectDeleted()
onObjectMetadataUpdated()

Copy link
Contributor

@taeold taeold left a comment

Choose a reason for hiding this comment

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

Minor nits. Hoping we can find a way to reduce some repetition in code.

Comment on lines 27 to 38
/** @hidden */
export const provider = 'google.cloud.storage';
/** @hidden */
export const service = 'storage.googleapis.com';
/** @hidden */
export const archivedEvent = 'object.v1.archived';
/** @hidden */
export const finalizedEvent = 'object.v1.finalized';
/** @hidden */
export const deletedEvent = 'object.v1.deleted';
/** @hidden */
export const metadataUpdatedEvent = 'object.v1.metadataUpdated';
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to export these constants?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm using them in the unit tests

Comment on lines 69 to 80
if (arguments.length === 1) {
handler = optsOrHandler as (
event: CloudEvent<StorageObjectData>
) => any | Promise<any>;
_onOperation(handler, archivedEvent);
}
return _onOperation(
handler,
archivedEvent,
optsOrHandler as string | StorageOptions
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm, it looks like we repeat this block for each of the four event type. It would be cool if we can contain all "make sure we handle optOrHandler appropriately in _onOperation; can we start a discussion in our chat room to see if there's a clever TS thing we can do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've cleaned it up and moved the logic into _onOperation. The 4 functions now only serve to inject the correct event type.

* An object within Google Cloud Storage.
* Ref: https://github.com/googleapis/google-cloudevents-nodejs/blob/main/cloud/storage/v1/StorageObjectData.ts
*/
export interface StorageObjectData {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit* Can this be declared at the top of the file instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to the top

},
eventTrigger: {
eventType: provider + '.' + eventType,
resource: bucket, // TODO(colerogers): replace with bucket: 'my-bucket' when container contract is finished
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you expand on what you mean by this TODO? I'm a confused by the suggestion that we should set this to a constant my-bucket. Also probably better to leave out mentioning container contract here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, I removed the CC part. Eventually, we'll need to remove the resource field and just map to a bucket field.

Comment on lines 262 to 263
'Missing bucket name. If you are unit testing, please provide a bucket name' +
' through set process.env.FIREBASE_CONFIG.'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'Missing bucket name. If you are unit testing, please provide a bucket name' +
' through set process.env.FIREBASE_CONFIG.'
'Missing bucket name. If you are unit testing, please provide a bucket name' +
' by providing bucket name directly in the event handler or by setting process.env.FIREBASE_CONFIG.'
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

): CloudFunction<StorageObjectData>;

export function onObjectMetadataUpdated(
optsOrHandler:
Copy link
Contributor

Choose a reason for hiding this comment

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

nits* It's a mouthful, but I think I would prefer butcketOrOptsOrHandler for accuracy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense, fixed

};

beforeEach(() => {
options.setGlobalOptions({});
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems redundant no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed


beforeEach(() => {
options.setGlobalOptions({});
process.env.GCLOUD_PROJECT = 'aProject';
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm can you remind me why setting this environment variable is required for the test to work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we don't set it, then when we try and perform optionsToTriggerAnnotations it will call serviceAccountFromShorthand which requires this env var to be set and throw an error otherwise

Comment on lines 45 to 49
const EVENT_TRIGGER = {
eventType: 'google.cloud.storage.event-type',
resource: 'my-bucket',
service: 'storage.googleapis.com',
};
Copy link
Contributor

Choose a reason for hiding this comment

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

nit* I'd make this module-level constant instead of scoping it to this test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to the top and added in specific event constants for each event type.

},
regions: ['us-west1'],
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we also test where opt is provided without a bucket property?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added tests for each event type tests and the onOperation tests.

handler: (event: CloudEvent<StorageObjectData>) => any | Promise<any>
): CloudFunction<StorageObjectData>;

/** Handle a storage object archived */
Copy link
Contributor

Choose a reason for hiding this comment

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

ugh does ESLint for us to repeat JSDoc comment on each of the overloaded function 🤦‍♂️ ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was following what we did with pubsub, but since GCS has a lot more overloads, I removed the repeated ones and left the top comment.

Comment on lines 302 to 304
// handler: (event: CloudEvent<StorageObjectData>) => any | Promise<any>,
// eventType: string,
// bucketOrOpts?: string | StorageOptions
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// handler: (event: CloudEvent<StorageObjectData>) => any | Promise<any>,
// eventType: string,
// bucketOrOpts?: string | StorageOptions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, removed

| ((event: CloudEvent<StorageObjectData>) => any | Promise<any>),
handler?: (event: CloudEvent<StorageObjectData>) => any | Promise<any>
): CloudFunction<StorageObjectData> {
if (arguments.length === 2) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't there a subtle bug here since _onOperation is always called with 3 arguments now?

e.g.

> function foo(a, b) { return arguments.length }
undefined
> foo(1)
1
> foo(1, 2)
2
> foo(1, undefined)
2

So I'd expect arguments.length to always be 3

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this will work:

if (typeof bucketOrOptsOrHandler === "function") {
  ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh dang, yeah that's a bug alright. For some reason in my head passing an undefined handler was equivalent to leaving off the last parameter. Thanks for catching this!

Copy link
Contributor

@taeold taeold left a comment

Choose a reason for hiding this comment

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

lgtm; I'd recommend we wait until @inlined review as this is our first major enhancement on v2 provider namespace outside of his code.

Copy link
Member

@inlined inlined left a comment

Choose a reason for hiding this comment

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

Sorry... I reviewed this a while ago and never hit "submit"

package.json Show resolved Hide resolved
spec/v2/providers/storage.spec.ts Outdated Show resolved Hide resolved
spec/v2/providers/storage.spec.ts Outdated Show resolved Hide resolved
src/v2/providers/storage.ts Outdated Show resolved Hide resolved
}

/** @hidden */
export function _getOptsAndBucket(
Copy link
Member

Choose a reason for hiding this comment

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

While you'll still find _ prefixes in old codebases, that was pre access-control. Also, I think you can use @internal instead of @hidden (would need to double check that it doesn't show up in docs).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the _ prefixes and changed to using @internal. The typedoc docs indicate that both hidden and internal will remove from the code from documentation as long as we don't pass in --excludeInternal.

@colerogers colerogers merged commit 0479817 into master Sep 30, 2021
@colerogers colerogers deleted the colerogers.gcs-enhancement branch September 30, 2021 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants