diff --git a/components/server/src/github/api.ts b/components/server/src/github/api.ts index 07ba99f9814b64..9c4c41cca06a3d 100644 --- a/components/server/src/github/api.ts +++ b/components/server/src/github/api.ts @@ -156,7 +156,7 @@ export class GitHubRestApi { } protected get userAgent() { - return new URL(this.config.oauth!.callBackUrl).hostname; + return (this.config.oauth && new URL(this.config.oauth?.callBackUrl)?.hostname) || "GitPod unknown"; } /** diff --git a/components/server/src/github/file-provider.ts b/components/server/src/github/file-provider.ts index 6421570398edc3..9f8b05afa85290 100644 --- a/components/server/src/github/file-provider.ts +++ b/components/server/src/github/file-provider.ts @@ -8,12 +8,11 @@ import { injectable, inject } from "inversify"; import { FileProvider, MaybeContent } from "../repohost/file-provider"; import { Commit, User, Repository } from "@gitpod/gitpod-protocol"; -import { GitHubGraphQlEndpoint, GitHubRestApi } from "./api"; +import { GitHubRestApi } from "./api"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; @injectable() export class GithubFileProvider implements FileProvider { - @inject(GitHubGraphQlEndpoint) protected readonly githubGraphQlApi: GitHubGraphQlEndpoint; @inject(GitHubRestApi) protected readonly githubApi: GitHubRestApi; public async getGitpodFileContent(commit: Commit, user: User): Promise { @@ -56,14 +55,27 @@ export class GithubFileProvider implements FileProvider { } try { - const contents = await this.githubGraphQlApi.getFileContents( - user, - commit.repository.owner, - commit.repository.name, - commit.revision, - path, + const response = await this.githubApi.run(user, (api) => + api.repos.getContent({ + owner: commit.repository.owner, + repo: commit.repository.name, + path, + ref: commit.revision, + headers: { + accept: "application/vnd.github.VERSION.raw", + }, + }), ); - return contents; + if (response.status === 200) { + if (typeof response.data === "string") { + return response.data; + } + console.warn("GithubFileProvider.getFileContent – unexpected response type.", { + headers: response.headers, + type: typeof response.data, + }); + } + return undefined; } catch (err) { log.debug(err); } diff --git a/components/server/src/github/github-file-provider.spec.ts b/components/server/src/github/github-file-provider.spec.ts new file mode 100644 index 00000000000000..a3cacfc4d2fa64 --- /dev/null +++ b/components/server/src/github/github-file-provider.spec.ts @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2022 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License-AGPL.txt in the project root for license information. + */ + +import { User } from "@gitpod/gitpod-protocol"; +import { skipIfEnvVarNotSet } from "@gitpod/gitpod-protocol/lib/util/skip-if"; +import { expect } from "chai"; +import { Container, ContainerModule } from "inversify"; +import { suite, retries, test, timeout } from "mocha-typescript"; +import { AuthProviderParams } from "../auth/auth-provider"; +import { DevData } from "../dev/dev-data"; +import { TokenProvider } from "../user/token-provider"; +import { GitHubRestApi } from "./api"; + +import { GithubFileProvider } from "./file-provider"; +import { GitHubTokenHelper } from "./github-token-helper"; + +@suite(timeout(10000), retries(2), skipIfEnvVarNotSet("GITPOD_TEST_TOKEN_GITHUB")) +class TestFileProvider { + static readonly AUTH_HOST_CONFIG: Partial = { + id: "Public-GitHub", + type: "GitHub", + verified: true, + description: "", + icon: "", + host: "github.com", + }; + + protected fileProvider: GithubFileProvider; + protected user: User; + protected container: Container; + + public before() { + this.container = new Container(); + this.container.load( + new ContainerModule((bind, unbind, isBound, rebind) => { + bind(GitHubRestApi).toSelf().inSingletonScope(); + bind(AuthProviderParams).toConstantValue(TestFileProvider.AUTH_HOST_CONFIG); + bind(GitHubTokenHelper).toSelf().inSingletonScope(); + bind(TokenProvider).toConstantValue({ + getTokenForHost: async () => DevData.createGitHubTestToken(), + getFreshPortAuthenticationToken: async (user: User, workspaceId: string) => + DevData.createPortAuthTestToken(workspaceId), + }); + bind(GithubFileProvider).toSelf().inSingletonScope(); + }), + ); + this.fileProvider = this.container.get(GithubFileProvider); + this.user = DevData.createTestUser(); + } + + @test public async testFileContent() { + const result = await this.fileProvider.getFileContent( + { + repository: { + owner: "gitpod-io", + name: "gitpod", + host: "github.com", + cloneUrl: "unused in test", + }, + revision: "af51739d341bb2245598e275336ae9f730e3b41a", + }, + this.user, + "License.txt", + ); + expect(result).to.not.be.undefined; + expect(result).to.contain(`To determine under which license you may use a file from the Gitpod source code, +please resort to the header of that file.`); + } +} + +module.exports = new TestFileProvider();