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

πŸŒ‡ GitHub App in Dashboard #19070

Merged
merged 3 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { useCurrentUser } from "../../user-context";

export const useIsGithubAppEnabled = () => {
return useQuery(["github-app-enabled"], async () => {
return await getGitpodService().server.isGitHubAppEnabled();
// similar to `isGitpodio`, but the GH App is only configured on Cloud.
return window.location.hostname === "gitpod.io" || window.location.hostname === "gitpod-staging.com";
});
};

Expand Down
100 changes: 5 additions & 95 deletions components/dashboard/src/projects/InstallGitHubApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,118 +4,28 @@
* See License.AGPL.txt in the project root for license information.
*/

import { useLocation } from "react-router";
import InfoBox from "../components/InfoBox";
import Modal from "../components/Modal";
import { Deferred } from "@gitpod/gitpod-protocol/lib/util/deferred";
import { getGitpodService, gitpodHostUrl } from "../service/service";
import { useState } from "react";
import { openAuthorizeWindow } from "../provider-utils";

async function registerApp(installationId: string, setModal: (modal: "done" | string | undefined) => void) {
try {
await getGitpodService().server.registerGithubApp(installationId);

const result = new Deferred<void>(1000 * 60 * 10 /* 10 min */);

openAuthorizeWindow({
host: "github.com",
scopes: ["repo"],
onSuccess: () => {
setModal("done");
result.resolve();
},
onError: (payload) => {
let errorMessage: string;
if (typeof payload === "string") {
errorMessage = payload;
} else {
errorMessage = payload.description ? payload.description : `Error: ${payload.error}`;
}
setModal(errorMessage);
},
});

return result.promise;
} catch (e) {
setModal(e.message);
}
}
import { gitpodHostUrl } from "../service/service";

export default function InstallGitHubApp() {
const location = useLocation();
const [modal, setModal] = useState<"done" | string | undefined>();
const params = new URLSearchParams(location.search);
const installationId = params.get("installation_id") || undefined;
if (!installationId) {
return (
<div className="app-container flex flex-col space-y-2">
<div className="px-6 py-3 flex justify-between space-x-2 text-gray-400 border-t border-gray-200 dark:border-gray-800 h-96">
<div className="flex flex-col items-center w-96 m-auto">
<h3 className="text-center pb-3 text-gray-500 dark:text-gray-400">No Installation ID Found</h3>
<div className="text-center pb-6 text-gray-500">
Did you come here from the GitHub app's page?
</div>
</div>
</div>
</div>
);
}

const goToApp = () => (window.location.href = gitpodHostUrl.toString());

return (
<>
<div className="app-container flex flex-col space-y-2">
<div className="px-6 py-3 flex justify-between space-x-2 text-gray-400">
<div className="flex flex-col items-center m-auto max-w-lg mt-40">
<h3 className="text-center pb-3 text-gray-500">Install GitHub App</h3>
<h3 className="text-center pb-3 text-gray-500">GitHub App πŸŒ…</h3>
<div className="text-center pb-6 text-gray-500">
You are about to install the GitHub app for Gitpod.
You likely tried to install the GitHub App for Gitpod.
</div>
<InfoBox>
This action will also allow Gitpod to access private repositories. You can edit Git provider
permissions later in user settings.
</InfoBox>
<InfoBox>Gitpod no longer requires to install the GitHub App on repositories.</InfoBox>
<div className="mt-6">
<button className="secondary">Cancel</button>
<button className="ml-2" onClick={() => registerApp(installationId, setModal)}>
Install App
</button>
<button onClick={goToApp}>Go to Dashboard</button>
</div>
</div>
</div>
</div>
<Modal
title="Installation Successful"
visible={modal === "done"}
onClose={goToApp}
buttons={<button onClick={goToApp}>Go to Dashboard</button>}
>
<div className="pb-6 text-gray-500">
The GitHub app was installed successfully. Have a look at the{" "}
<a className="text-blue-500" href="https://www.gitpod.io/docs/prebuilds/" rel="noopener">
documentation
</a>{" "}
to find out how to configure it.
</div>
</Modal>
<Modal
title="Failed to Install"
visible={!!modal && modal !== "done"}
onClose={goToApp}
buttons={[
<button className="secondary" onClick={goToApp}>
Cancel
</button>,
<button className="" onClick={() => registerApp(installationId, setModal)}>
Try Again
</button>,
]}
>
<div className="pb-6 text-gray-500">Could not install the GitHub app.</div>
<InfoBox>{modal}</InfoBox>
</Modal>
</>
);
}
2 changes: 2 additions & 0 deletions components/gitpod-protocol/src/gitpod-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
deleteGitpodToken(tokenHash: string): Promise<void>;

// misc
/** @deprecated always returns false */
isGitHubAppEnabled(): Promise<boolean>;
akosyakov marked this conversation as resolved.
Show resolved Hide resolved
/** @deprecated this is a no-op */
registerGithubApp(installationId: string): Promise<void>;

/**
Expand Down
21 changes: 2 additions & 19 deletions components/server/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

import {
AppInstallationDB,
UserDB,
WorkspaceDB,
DBWithTracing,
Expand Down Expand Up @@ -224,8 +223,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {

@inject(LinkedInService) private readonly linkedInService: LinkedInService,

@inject(AppInstallationDB) private readonly appInstallationDB: AppInstallationDB,

@inject(AuthProviderService) private readonly authProviderService: AuthProviderService,

@inject(GitTokenScopeGuesser) private readonly gitTokenScopeGuesser: GitTokenScopeGuesser,
Expand Down Expand Up @@ -1849,24 +1846,10 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
}

async isGitHubAppEnabled(ctx: TraceContext): Promise<boolean> {
await this.checkAndBlockUser();
return !!this.config.githubApp?.enabled;
return false;
}

async registerGithubApp(ctx: TraceContext, installationId: string): Promise<void> {
traceAPIParams(ctx, { installationId });

const user = await this.checkAndBlockUser();

if (!this.config.githubApp?.enabled) {
throw new ApplicationError(
ErrorCodes.NOT_FOUND,
"No GitHub app enabled for this installation. Please talk to your administrator.",
);
}

await this.appInstallationDB.recordNewInstallation("github", "user", installationId, user.id);
}
async registerGithubApp(ctx: TraceContext, installationId: string): Promise<void> {}

async takeSnapshot(ctx: TraceContext, options: GitpodServer.TakeSnapshotOptions): Promise<string> {
traceAPIParams(ctx, { options });
Expand Down
Loading