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

batches: create GitHub App UX flow#52979

Merged
courier-new merged 32 commits into
batches/commit-signingfrom
kr/ux-create-app-2
Jun 12, 2023
Merged

batches: create GitHub App UX flow#52979
courier-new merged 32 commits into
batches/commit-signingfrom
kr/ux-create-app-2

Conversation

@courier-new

@courier-new courier-new commented Jun 6, 2023

Copy link
Copy Markdown
Contributor

Closes https://github.com/sourcegraph/sourcegraph/issues/52223, https://github.com/sourcegraph/sourcegraph/issues/52220, https://github.com/sourcegraph/sourcegraph/issues/52475.

Walkthrough

Code walkthrough time, because it's a fairly chunky diff! Let's start at the front of the front and loop our way around.

CreateGitHubAppPage - [code]

  • This component is now configurable to different GH App contexts via a series of props, everything from which permissions to send for the new GH App manifest to the page headers to a URL validation function.
  • The "Create" form now gives better clientside validation, such as when the GitHub instance URL is invalid, or your app name is too long (GitHub requires it be 34 characters or less).
  • Some of the copy has been updated to read more clearly and better reflect the language used on the GitHub side of things.

BatchChangesCreateGitHubAppPage - [code]

  • This component is a wrapper around CreateGitHubAppPage for specifically the BC App context. It provides a custom URL validation function to ensure the provided URL is from a unique host as well as sets the manifest details, page header, "batches" App domain, and base URL.
  • You can review how this page differs from the initial "Repos" one in the first set of demo videos below.

CommitSigningIntegrationNode - [code]

  • Hooked up the "Create" and "Remove" buttons.

batches/resolvers/code_host.go - [code]

  • Surfaced the GitHub App id and base_url properties to the GraphQL type. The former is needed for the mutation to delete the App, and the latter is needed to validate that the URL an admin inputs when creating a new App is unique.

githubappauth/middleware.go - [code]

  • Brought over Bolaji's PR to support different redirects for different App domains.
  • Cleaned up some error handling.
  • I changed how the redirect in the final stages of the setup works slightly. Before, if anything were to error out in this stage of the process, it would just return a bare, plain response with the text error message, stranding the user at an internal URL like https://sourcegraph.test:3443/.auth/githubapp/setup... and requiring them to manually get themselves back to Sourcegraph and figure out what to do next. Now if an error occurs, we will attempt to redirect the user back to the appropriate GitHub Apps site admin page and surface the exact error message in the UI. You can see this in action in the 2nd and 3rd failure path demo videos below.

GitHubFailureAlert - [code]

  • This is the common component used to render one of those middleware errors from the UI.

Demo videos

Success path, creating a GitHub App. I recorded creating for repos here, too, just to confirm nothing broke:

Batch Changes Repos
Screen.Recording.2023-06-07.at.12.16.48.AM.mov
Screen.Recording.2023-06-07.at.12.14.54.AM.mov

Failure path, where we failed to create the initial state to use for initiating the GitHub App creation process:

Batch Changes Repos
Screen.Recording.2023-06-06.at.11.51.07.PM.mov
Screen.Recording.2023-06-06.at.11.53.45.PM.mov

Failure path, where we got all the way through to validating the setup and recording the new installation, but failed before we could ascertain the domain that the new GitHub App was intended for:

Batch Changes Repos
Screen.Recording.2023-06-06.at.11.40.13.PM.mov
Screen.Recording.2023-06-06.at.11.57.54.PM.mov

Failure path, where we got all the way through to validating the setup and recording the new installation, but something went wrong at the very last step:

Batch Changes Repos
Screen.Recording.2023-06-06.at.11.44.09.PM.mov
Screen.Recording.2023-06-07.at.12.01.16.AM.mov

Test plan

Extensive manual testing with a variety of forced failure breakpoints. Middleware unit tests updated.

@courier-new courier-new self-assigned this Jun 6, 2023
@cla-bot cla-bot Bot added the cla-signed label Jun 6, 2023
@courier-new courier-new added batch-changes Issues related to Batch Changes batches-signed-commit labels Jun 6, 2023
@courier-new courier-new changed the title Make GH App manifest events/permissions prop-configurable batches: create GitHub App UX flow Jun 6, 2023
@courier-new courier-new force-pushed the kr/ux-create-app-2 branch from 3a0de1d to bb1df55 Compare June 6, 2023 23:21
Base automatically changed from kr/ux-create-app to batches/commit-signing June 7, 2023 01:41
commit c3b078c
Author: BolajiOlajide <cooproton@gmail.com>
Date:   Sat Jun 3 22:29:17 2023 +0100

    update batches redirect url

commit 30f8985
Author: BolajiOlajide <cooproton@gmail.com>
Date:   Sat Jun 3 22:27:12 2023 +0100

    bazel it

commit e4e734c
Author: BolajiOlajide <cooproton@gmail.com>
Date:   Sat Jun 3 21:57:39 2023 +0100

    add tests for middleware

commit 80855ed
Author: BolajiOlajide <cooproton@gmail.com>
Date:   Sat Jun 3 16:18:46 2023 +0100

    add tests

commit 5b3c0f8
Author: BolajiOlajide <cooproton@gmail.com>
Date:   Tue May 30 17:54:42 2023 +0100

    handle redirect for batches app
@courier-new courier-new force-pushed the kr/ux-create-app-2 branch from f7c74ed to ec71e29 Compare June 7, 2023 04:37
@courier-new courier-new force-pushed the kr/ux-create-app-2 branch from 4c480a6 to 28a3f70 Compare June 7, 2023 18:11
Comment on lines +130 to +136
if (!response.ok) {
if (response.body instanceof ReadableStream) {
const error = await response.text()
throw new Error(error)
}
}
const state = (await response.json()) as StateResponse

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.

The errors we respond with from the server middleware are plain text, not JSON. Prior to this change, middleware errors would surface in the UI as confusing JSON parsing errors:

image

This ensures a middleware response error is properly handled. Check out the demo videos to see it!

Comment on lines +138 to +143
if (state.webhookUUID?.length) {
webhookURL = new URL(`/.api/webhooks/${state.webhookUUID}`, originURL).href
}
if (!state.state?.length) {
throw new Error('Response from server missing state parameter')
}

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.

Covering our grounds here rather than blindly assuming what we got back from the server was a StateResponse.

Comment on lines +173 to +177
try {
new URL(trimmedURL)
} catch {
return setUrlError('URL is not valid.')
}

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.

This ensures the GitHub URL an admin input is actually a valid URL. Before if you made a typo it would just... completely blow up 😂

Screen.Recording.2023-06-07.at.10.29.11.AM.mov

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.

Omgosh. Good fix!

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.

Tests from Bolaji's PR, thank you Bolaji!! 🙌 The only part that's new since my PR is the addition of several test cases for GenerateRedirectURL to ensure a redirect URL is still returned with an error message encoded as a URL parameter now.

Comment on lines +54 to +70
{
name: "invalid domain",
domain: &invalidDomain,
expectedURL: "/site-admin/github-apps?success=false&error=invalid+domain%3A+invalid",
},
{
name: "repos creation error",
domain: &reposDomain,
creationErr: creationErr,
expectedURL: "/site-admin/github-apps?success=false&error=uh+oh%21",
},
{
name: "batches creation error",
domain: &batchesDomain,
creationErr: creationErr,
expectedURL: "/site-admin/batch-changes?success=false&error=uh+oh%21",
},

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.

The new test cases.

Comment on lines 82 to 90
/>
{error && <ErrorAlert className="mt-4 mb-0 text-left" error={error} />}
{!success && setupError && <GitHubAppFailureAlert error={setupError} />}
<ConnectionContainer>
{error && <ErrorAlert error={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.

The existing error here from the connection was actually redundant with the one on line 84/90.

Comment on lines -203 to +271
<Button
variant="primary"
onClick={createState}
disabled={name.trim().length < 3 || url.trim().length < 10}
>
<Button variant="primary" onClick={createState} disabled={!!nameError || !!urlError}>

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.

The condition to disable the button here was arbitrary and didn't provide any feedback to the user as to why it was disabled. I've replaced it with actual per-input validation using <Input status="error" error={...} /> and updated this condition to disable the button corresponding with either of those input errors being present.

@courier-new courier-new marked this pull request as ready for review June 7, 2023 18:12
@courier-new courier-new requested review from a team, kopancek and pjlast June 7, 2023 18:13
@courier-new

Copy link
Copy Markdown
Contributor Author

@pjlast @kopancek tagging you just in case you want to review the middleware changes. Don't feel like you need to give an exhaustive review of the batches stuff. 🙂

@sourcegraph-bot

sourcegraph-bot commented Jun 7, 2023

Copy link
Copy Markdown
Contributor

Codenotify: Notifying subscribers in CODENOTIFY files for diff fc8071b...262bc44.

Notify File(s)
@BolajiOlajide client/web/src/enterprise/batches/settings/BatchChangesCreateGitHubAppPage.tsx
client/web/src/enterprise/batches/settings/BatchChangesSettingsArea.story.tsx
client/web/src/enterprise/batches/settings/BatchChangesSiteConfigSettingsPage.story.tsx
client/web/src/enterprise/batches/settings/BatchChangesSiteConfigSettingsPage.tsx
client/web/src/enterprise/batches/settings/CommitSigningIntegrationNode.tsx
client/web/src/enterprise/batches/settings/CommitSigningIntegrations.tsx
client/web/src/enterprise/batches/settings/backend.ts
@eseliger client/web/src/enterprise/batches/settings/BatchChangesCreateGitHubAppPage.tsx
client/web/src/enterprise/batches/settings/BatchChangesSettingsArea.story.tsx
client/web/src/enterprise/batches/settings/BatchChangesSiteConfigSettingsPage.story.tsx
client/web/src/enterprise/batches/settings/BatchChangesSiteConfigSettingsPage.tsx
client/web/src/enterprise/batches/settings/CommitSigningIntegrationNode.tsx
client/web/src/enterprise/batches/settings/CommitSigningIntegrations.tsx
client/web/src/enterprise/batches/settings/backend.ts
cmd/frontend/graphqlbackend/batches.go
@unknwon enterprise/cmd/frontend/internal/auth/githubappauth/BUILD.bazel
enterprise/cmd/frontend/internal/auth/githubappauth/middleware.go
enterprise/cmd/frontend/internal/auth/githubappauth/middleware_test.go
enterprise/cmd/frontend/internal/auth/githubappauth/resolver_test.go

@sourcegraph-bot

sourcegraph-bot commented Jun 7, 2023

Copy link
Copy Markdown
Contributor

📖 Storybook live preview

@courier-new

Copy link
Copy Markdown
Contributor Author

Hmm, not sure why buildkite is showing test failures. Those tests are passing locally:

image

And the buildkite output doesn't show why the test failed. 😞

Comment thread enterprise/cmd/frontend/internal/auth/githubappauth/middleware_test.go Outdated
@courier-new

Copy link
Copy Markdown
Contributor Author

Okay build is finally all green again!! 😌

@st0nebreaker st0nebreaker 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 really good!

I tested through the happy path and all is gucci. For the sad paths you featured in your description, is there a clear way to trigger those or did you have to manually change parts of the code/setup to get that? I don't need to test the failure path flow, just curious, and the added tests/flows you tested give me confidence.

Comment on lines +173 to +177
try {
new URL(trimmedURL)
} catch {
return setUrlError('URL is not valid.')
}

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.

Omgosh. Good fix!

Comment on lines +400 to +424
switch *parsedDomain {
case types.ReposGitHubAppDomain:
if creationErr != nil {
return fmt.Sprintf("/site-admin/github-apps?success=false&error=%s", url.QueryEscape(creationErr.Error()))
}
if installationID == nil || appID == nil {
return fmt.Sprintf("/site-admin/github-apps?success=false&error=%s", url.QueryEscape("missing installation ID or app ID"))
}

return fmt.Sprintf("/site-admin/github-apps/%s?installation_id=%d", MarshalGitHubAppID(int64(*appID)), *installationID)
case types.BatchesGitHubAppDomain:
if creationErr != nil {
return fmt.Sprintf("/site-admin/batch-changes?success=false&error=%s", url.QueryEscape(creationErr.Error()))
}

// This shouldn't really happen unless we also had an error, but we handle it just
// in case
if appName == nil {
return "/site-admin/batch-changes?success=true"
}
return fmt.Sprintf("/site-admin/batch-changes?success=true&app_name=%s", *appName)
default:
return fmt.Sprintf("/site-admin/github-apps?success=false&error=%s", url.QueryEscape(fmt.Sprintf("unsupported github apps domain: %v", parsedDomain)))
}
}

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.

Love this redirect logic & passing the success & error info through query params!

Comment thread enterprise/cmd/frontend/internal/auth/githubappauth/middleware.go
Comment thread client/web/src/enterprise/batches/settings/CommitSigningIntegrationNode.tsx Outdated
@courier-new

Copy link
Copy Markdown
Contributor Author

For the sad paths you featured in your description, is there a clear way to trigger those or did you have to manually change parts of the code/setup to get that? I don't need to test the failure path flow, just curious, and the added tests/flows you tested give me confidence.

Yeah I was manually forcing failures to happen by changing the middleware code at various points. It's not too annoying if you're interested in playing around with it. If you find the handler for the /setup endpoint:

r.HandleFunc(prefix+"/setup", ...

Anywhere there's an error code path that's normally behind a condition, e.g.

if err != nil {
	redirectURL := generateRedirectURL(nil, nil, nil, nil, errors.New("Bad request, invalid state"))
	http.Redirect(w, req, redirectURL, http.StatusFound)
	return
}

I'd just comment out the condition to test what it would be like to fail at that point:

// if err != nil {
redirectURL := generateRedirectURL(nil, nil, nil, nil, errors.New("Bad request, invalid state"))
http.Redirect(w, req, redirectURL, http.StatusFound)
return
// }

@BolajiOlajide BolajiOlajide 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.

Code-wise, this looks good to me. Thanks for the detailed explanation.

Just need to figure out why I get a nil response from createCommitFromPatch

Comment thread enterprise/cmd/frontend/internal/auth/githubappauth/middleware.go

@pjlast pjlast 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.

Amazing PR, thanks for all the tweaks and polish and the super detailed code walk through 🙏

@courier-new

courier-new commented Jun 12, 2023

Copy link
Copy Markdown
Contributor Author

@st0nebraker I'm going to go ahead and merge this and start rebasing the other ones, but still feel free to leave any additional feedback and I can gladly address it in a follow-up!! 😄 NEVERMIND I spoke a second too late, thanks for the review haha!!

@courier-new courier-new merged commit 09b07ba into batches/commit-signing Jun 12, 2023
@courier-new courier-new deleted the kr/ux-create-app-2 branch June 12, 2023 15:29
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.

5 participants