Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

batches: construct webhook payload via GraphQL request - #46967

Merged
BolajiOlajide merged 17 commits into
mainfrom
bo/construct-webhooks-payload-with-graphql
Feb 27, 2023
Merged

batches: construct webhook payload via GraphQL request#46967
BolajiOlajide merged 17 commits into
mainfrom
bo/construct-webhooks-payload-with-graphql

Conversation

@BolajiOlajide

@BolajiOlajide BolajiOlajide commented Jan 26, 2023

Copy link
Copy Markdown
Contributor

Closes #46989

Test plan

Tested locally using webhook.site, and it looks good.

batch_change_apply CleanShot 2023-01-26 at 01 19 30@2x
changeset_publish CleanShot 2023-01-26 at 01 18 18@2x

CleanShot 2023-02-23 at 16 09 04
CleanShot 2023-02-23 at 16 08 58

@BolajiOlajide BolajiOlajide added the batch-changes Issues related to Batch Changes label Jan 26, 2023
@BolajiOlajide
BolajiOlajide requested a review from a team January 26, 2023 00:21
@BolajiOlajide BolajiOlajide self-assigned this Jan 26, 2023
@cla-bot cla-bot Bot added the cla-signed label Jan 26, 2023
@sourcegraph-bot

sourcegraph-bot commented Jan 26, 2023

Copy link
Copy Markdown
Contributor

Codenotify: Notifying subscribers in CODENOTIFY files for diff 7e39581...9e78379.

Notify File(s)
@eseliger enterprise/internal/batches/processor/bulk_processor.go
enterprise/internal/batches/reconciler/executor.go
enterprise/internal/batches/service/service.go
enterprise/internal/batches/service/service_apply_batch_change.go
enterprise/internal/batches/webhooks/batch_change.go
enterprise/internal/batches/webhooks/batch_change_test.go
enterprise/internal/batches/webhooks/changeset.go
enterprise/internal/batches/webhooks/changeset_test.go
enterprise/internal/batches/webhooks/gql.go
enterprise/internal/batches/webhooks/util.go
enterprise/internal/batches/webhooks/webhooks.go

@eseliger eseliger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice, feels super clean :)

@courier-new

Copy link
Copy Markdown
Contributor

Hmm, y'know, this is cool and all, but I admit when Erik first suggested the idea, I guess imagined this looking a bit different. 😅 I was kinda hoping that would mean a net reduction of lines of code, maybe that was naive of me... 😂 It's also kinda unfortunate now that there's three places you would have to update the next time we add another field on a batch change.

But I'd love to understand better! So the main benefit we're getting here is that we no longer have to duplicate the namespace marshaling logic or any of the other little things to marshal values into JSON-friendly format? Are there other benefits? 🙂

SyncerError *string `json:"syncer_error"`
}

func MarshalChangeset(ctx context.Context, db basestore.ShareableStore, cs *types.Changeset) ([]byte, error) {

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.

Am I missing something here? It looks like MarshalChangeset is still just creating the changeset body payload manually, not with an internal GraphQL request.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

oh 🤔

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.

@BolajiOlajide would we be able to do the same internal GraphQL query thing for MarshalChangeset, too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I can do that.

How about another approach? Since we can depend on the GraphQL schema to construct the webhook payload, how about we change the signature of the MarshalX method to take in a graphql.ID as the last parameter instead of the full struct. That way func MarshalChangeset(ctx context.Context, cs *types.Changeset) ([]byte, error) becomes func MarshalChangeset(ctx context.Context, id graphql.ID) ([]byte, error) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What do you think @courier-new @eseliger ?

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.

I think we talked about this in Barcelona but just wanted to put it on the record here, too -- that sounds good to me!

@eseliger

Copy link
Copy Markdown
Member

But I'd love to understand better! So the main benefit we're getting here is that we no longer have to duplicate the namespace marshaling logic or any of the other little things to marshal values into JSON-friendly format? Are there other benefits? 🙂

I think it has a bunch of benefits actually IMO:

  • No duplication of computed field values if the computation lives in the graphql layer
  • No divergence between webhook and graphql response possible
  • We get permission checks "for free" because the graphql request honors the user account in the context
  • No change of payload if the type changes, making it more stable (yes we have to add it here explicitly, but that actually feels very intentional so I don't dislike that)

How do you feel about that?

@Piszmog

Piszmog commented Jan 26, 2023

Copy link
Copy Markdown
Contributor

Could you elaborate a bit more on,

We get permission checks "for free" because the graphql request honors the user account in the context

I thought webhooks are configured with just a secret at the site admin level.

@eseliger

Copy link
Copy Markdown
Member

I thought webhooks are configured with just a secret at the site admin level.

Ah, I guess that doesn't give us a lot of benefit then today :D when we start allowing webhooks on the user-level as well (site-admin is pretty clunky imo and puts a lot of config burden on often a single individual) it'll help 🤷

@BolajiOlajide

Copy link
Copy Markdown
Contributor Author

I thought webhooks are configured with just a secret at the site admin level.

Ah, I guess that doesn't give us a lot of benefit then today :D when we start allowing webhooks on the user-level as well (site-admin is pretty clunky imo and puts a lot of config burden on often a single individual) it'll help 🤷

Yeah, I misunderstood the secrets aspect, also. Let's close this Pull Request and the associated issue.
One of the reasons I agreed with this approach initially was because it helped with the validation of fields and also ensured whatever fields we were fetching matched what the resolvers would typically return.

@eseliger

Copy link
Copy Markdown
Member

I didn't mean to say this doesn't have other benefits, it just doesn't give the benefit of the deduplication of security today. I still think this is a valid approach overall to computing these payloads 🤷

@BolajiOlajide

BolajiOlajide commented Jan 27, 2023

Copy link
Copy Markdown
Contributor Author

I didn't mean to say this doesn't have other benefits, it just doesn't give the benefit of the deduplication of security today. I still think this is a valid approach overall to computing these payloads 🤷

Yeah, I 💯 agree with that..

@courier-new

Copy link
Copy Markdown
Contributor

Yes, that does feel like a good set of benefits. 🙂

No change of payload if the type changes, making it more stable (yes we have to add it here explicitly, but that actually feels very intentional so I don't dislike that)

I am just a bit concerned about this one, though -- I agree, I like the intentionality behind it, but I worry it'll be very easy to forget to make changes over here when the primary GraphQL type changes, especially if someone other than the 4 of us in this discussion is making the change. It's probably worth us adding some inline comments to the BatchChange and Changeset types to hopefully catch the eye of anyone adding/changing properties there, to at least make them aware of this corresponding payload and remind them to consider making the equivalent changes here.

@eseliger

Copy link
Copy Markdown
Member

We could also argue that it gives stability to the payload and that we intentionally expose new fields, and also get alerted (because the query would fail) if a field would be not available anymore which would break the webhook payload API contract. I'm not feeling super strongly about this, but figured I'd leave a note on that here :)

BolajiOlajide added a commit that referenced this pull request Feb 20, 2023
This is a part of #46967. `ForkName` is one of the fields on the webhook
payload for a changeset, we don't currently expose `ForkName` via the
GraphQL API, this PR fixes that.

## Test plan

<!-- All pull requests REQUIRE a test plan:
https://docs.sourcegraph.com/dev/background-information/testing_principles
-->
* Manually tested
* Update unit tests for forked changesets

<img width="1199" alt="CleanShot 2023-02-20 at 19 30 43@2x"
src="https://user-images.githubusercontent.com/25608335/220178496-7f7a19b6-4c85-4714-8f13-2aceab9cc1dc.png">

---------

Co-authored-by: Kelli Rockwell <kelli@sourcegraph.com>
courier-new added a commit that referenced this pull request Feb 21, 2023
This is a part of #46967. `ForkName` is one of the fields on the webhook
payload for a changeset, we don't currently expose `ForkName` via the
GraphQL API, this PR fixes that.

## Test plan

<!-- All pull requests REQUIRE a test plan:
https://docs.sourcegraph.com/dev/background-information/testing_principles
-->
* Manually tested
* Update unit tests for forked changesets

<img width="1199" alt="CleanShot 2023-02-20 at 19 30 43@2x"
src="https://user-images.githubusercontent.com/25608335/220178496-7f7a19b6-4c85-4714-8f13-2aceab9cc1dc.png">

---------

Co-authored-by: Kelli Rockwell <kelli@sourcegraph.com>
BolajiOlajide referenced this pull request Feb 23, 2023
This is also a part of
https://github.com/sourcegraph/sourcegraph/pull/46967. We need to expose
the id of the batch change that owns a changeset.

## Test plan

<!-- All pull requests REQUIRE a test plan:
https://docs.sourcegraph.com/dev/background-information/testing_principles
-->
* Manually tested
* Add unit tests
@BolajiOlajide
BolajiOlajide force-pushed the bo/construct-webhooks-payload-with-graphql branch from 5accb01 to fa7cd6e Compare February 25, 2023 17:33

@courier-new courier-new 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.

Looks great, thanks Bolaji! Just had 2 minor nits and a field name change suggestion.

Comment on lines +61 to +78
ID graphql.ID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
State string `json:"state"`
URL string `json:"url"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
LastAppliedAt *time.Time `json:"lastAppliedAt"`
ClosedAt *time.Time `json:"closedAt"`
Namespace struct {
ID graphql.ID `json:"id"`
} `json:"namespace"`
Creator struct {
ID graphql.ID `json:"id"`
} `json:"creator"`
LastApplier struct {
ID *graphql.ID `json:"id"`
} `json:"lastApplier"`

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.

Nittiest of nits: Would it be possible to order these fields in the same way that they're ordered in the corresponding GraphQL query string? Might make it 10% easier to add additional fields in the future.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure thing.

externalURL = &node.ExternalURL.URL
}

return json.Marshal(changeset{

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.

Same ordering ask about these fields.


return json.Marshal(&payload)
ForkName: node.ForkName,
OwningBatchChangeID: node.OwnedByBatchChange,

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.

I just noticed, shouldn't these field names match?

Suggested change
OwningBatchChangeID: node.OwnedByBatchChange,
OwnedByBatchChange: node.OwnedByBatchChange,

@BolajiOlajide
BolajiOlajide merged commit 906cc90 into main Feb 27, 2023
@BolajiOlajide
BolajiOlajide deleted the bo/construct-webhooks-payload-with-graphql branch February 27, 2023 11:20
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

batch-changes Issues related to Batch Changes cla-signed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Construct webhook payload via GraphQL

5 participants