-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Gitea support #8131
base: main
Are you sure you want to change the base?
Gitea support #8131
Changes from 3 commits
fb49a9e
1900190
86ba2fd
9fa680e
e505726
49ed017
7ae3857
5f50678
3ff0f29
1d75b9d
bd3bc15
45fec61
590ea08
f1bb3ca
b093367
ad2d2b2
b5ab0c9
944637a
9018b84
de29566
dc3fdc8
10a6b40
27da032
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** | ||
* Copyright (c) 2020 Gitpod GmbH. All rights reserved. | ||
* Licensed under the Gitpod Enterprise Source Code License, | ||
* See License.enterprise.txt in the project root folder. | ||
*/ | ||
|
||
import { ContainerModule } from "inversify"; | ||
import { GiteaService } from "../prebuilds/gitea-service"; | ||
import { RepositoryService } from "../../../src/repohost/repo-service"; | ||
|
||
export const giteaContainerModuleEE = new ContainerModule((_bind, _unbind, _isBound, rebind) => { | ||
rebind(RepositoryService).to(GiteaService).inSingletonScope(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** | ||
* Copyright (c) 2020 Gitpod GmbH. All rights reserved. | ||
* Licensed under the Gitpod Enterprise Source Code License, | ||
* See License.enterprise.txt in the project root folder. | ||
*/ | ||
|
||
import { AuthProviderInfo, ProviderRepository, User } from "@gitpod/gitpod-protocol"; | ||
import { inject, injectable } from "inversify"; | ||
import { TokenProvider } from "../../../src/user/token-provider"; | ||
import { UserDB } from "@gitpod/gitpod-db/lib"; | ||
import { Gitea } from "../../../src/gitea/api"; | ||
|
||
@injectable() | ||
export class GiteaAppSupport { | ||
|
||
@inject(UserDB) protected readonly userDB: UserDB; | ||
@inject(TokenProvider) protected readonly tokenProvider: TokenProvider; | ||
|
||
async getProviderRepositoriesForUser(params: { user: User, provider: AuthProviderInfo }): Promise<ProviderRepository[]> { | ||
const token = await this.tokenProvider.getTokenForHost(params.user, params.provider.host); | ||
const oauthToken = token.value; | ||
const api = Gitea.create(`https://${params.provider.host}`, oauthToken); | ||
|
||
const result: ProviderRepository[] = []; | ||
const ownersRepos: ProviderRepository[] = []; | ||
|
||
const identity = params.user.identities.find(i => i.authProviderId === params.provider.authProviderId); | ||
if (!identity) { | ||
return result; | ||
} | ||
const usersGitLabAccount = identity.authName; | ||
|
||
// cf. https://docs.gitlab.com/ee/api/projects.html#list-all-projects | ||
// we are listing only those projects with access level of maintainers. | ||
// also cf. https://docs.gitlab.com/ee/api/members.html#valid-access-levels | ||
// | ||
// TODO: check if valid | ||
const projectsWithAccess = await api.user.userCurrentListRepos({ limit: 100 }); | ||
for (const project of projectsWithAccess.data) { | ||
const path = project.full_name as string; | ||
const cloneUrl = project.clone_url as string; | ||
const updatedAt = project.updated_at as string; | ||
const accountAvatarUrl = project.owner?.avatar_url as string; | ||
const account = project.owner?.login as string; | ||
|
||
(account === usersGitLabAccount ? ownersRepos : result).push({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GitLab? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just copied the gitlab code and added some placeholders for the ee code yet. I am still quite new to the codebase of Gitpod, but hopefully the ee part is not to critical to run the server for now. |
||
name: project.name as string, | ||
path, | ||
account, | ||
cloneUrl, | ||
updatedAt, | ||
accountAvatarUrl, | ||
// inUse: // todo(at) compute usage via ProjectHooks API | ||
}) | ||
} | ||
|
||
// put owner's repos first. the frontend will pick first account to continue with | ||
result.unshift(...ownersRepos); | ||
return result; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/** | ||
* Copyright (c) 2020 Gitpod GmbH. All rights reserved. | ||
* Licensed under the Gitpod Enterprise Source Code License, | ||
* See License.enterprise.txt in the project root folder. | ||
*/ | ||
|
||
import * as express from 'express'; | ||
import { postConstruct, injectable, inject } from 'inversify'; | ||
import { ProjectDB, TeamDB, UserDB } from '@gitpod/gitpod-db/lib'; | ||
import { Project, User, StartPrebuildResult } from '@gitpod/gitpod-protocol'; | ||
import { PrebuildManager } from '../prebuilds/prebuild-manager'; | ||
import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing'; | ||
import { TokenService } from '../../../src/user/token-service'; | ||
import { HostContextProvider } from '../../../src/auth/host-context-provider'; | ||
// import { GiteaService } from './gitea-service'; | ||
import { log } from '@gitpod/gitpod-protocol/lib/util/logging'; | ||
|
||
@injectable() | ||
export class GiteaApp { | ||
|
||
@inject(UserDB) protected readonly userDB: UserDB; | ||
@inject(PrebuildManager) protected readonly prebuildManager: PrebuildManager; | ||
@inject(TokenService) protected readonly tokenService: TokenService; | ||
@inject(HostContextProvider) protected readonly hostCtxProvider: HostContextProvider; | ||
@inject(ProjectDB) protected readonly projectDB: ProjectDB; | ||
@inject(TeamDB) protected readonly teamDB: TeamDB; | ||
|
||
protected _router = express.Router(); | ||
public static path = '/apps/gitea/'; | ||
|
||
@postConstruct() | ||
protected init() { | ||
this._router.post('/', async (req, res) => { | ||
const event = req.header('X-Gitlab-Event'); | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (event === 'Push Hook') { | ||
const context = req.body as GitLabPushHook; | ||
const span = TraceContext.startSpan("GitLapApp.handleEvent", {}); | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
span.setTag("request", context); | ||
log.debug("GitLab push hook received", { event, context }); | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let user: User | undefined; | ||
try { | ||
user = await this.findUser({ span }, context, req); | ||
} catch (error) { | ||
log.error("Cannot find user.", error, { req }) | ||
} | ||
if (!user) { | ||
res.statusCode = 503; | ||
res.send(); | ||
return; | ||
} | ||
await this.handlePushHook({ span }, context, user); | ||
} else { | ||
log.debug("Unknown GitLab event received", { event }); | ||
} | ||
res.send('OK'); | ||
}); | ||
} | ||
|
||
protected async findUser(ctx: TraceContext, context: GitLabPushHook, req: express.Request): Promise<User> { | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// TODO | ||
return {} as User; | ||
} | ||
|
||
protected async handlePushHook(ctx: TraceContext, body: GitLabPushHook, user: User): Promise<StartPrebuildResult | undefined> { | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// TODO | ||
return undefined; | ||
} | ||
|
||
/** | ||
* Finds the relevant user account and project to the provided webhook event information. | ||
* | ||
* First of all it tries to find the project for the given `cloneURL`, then it tries to | ||
* find the installer, which is also supposed to be a team member. As a fallback, it | ||
* looks for a team member which also has a gitlab.com connection. | ||
* | ||
* @param cloneURL of the webhook event | ||
* @param webhookInstaller the user account known from the webhook installation | ||
* @returns a promise which resolves to a user account and an optional project. | ||
*/ | ||
protected async findProjectAndOwner(cloneURL: string, webhookInstaller: User): Promise<{ user: User, project?: Project }> { | ||
// TODO | ||
return {} as { user: User, project?: Project }; | ||
} | ||
|
||
protected createContextUrl(body: GitLabPushHook) { | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const repoUrl = body.repository.git_http_url; | ||
const contextURL = `${repoUrl.substr(0, repoUrl.length - 4)}/-/tree${body.ref.substr('refs/head/'.length)}`; | ||
return contextURL; | ||
} | ||
|
||
get router(): express.Router { | ||
return this._router; | ||
} | ||
|
||
protected getBranchFromRef(ref: string): string | undefined { | ||
const headsPrefix = "refs/heads/"; | ||
if (ref.startsWith(headsPrefix)) { | ||
return ref.substring(headsPrefix.length); | ||
} | ||
|
||
return undefined; | ||
} | ||
} | ||
|
||
interface GitLabPushHook { | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
object_kind: 'push'; | ||
before: string; | ||
after: string; // commit | ||
ref: string; // e.g. "refs/heads/master" | ||
user_avatar: string; | ||
user_name: string; | ||
project: GitLabProject; | ||
repository: GitLabRepository; | ||
} | ||
|
||
interface GitLabRepository { | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name: string, | ||
git_http_url: string; // e.g. http://example.com/mike/diaspora.git | ||
visibility_level: number, | ||
} | ||
|
||
interface GitLabProject { | ||
anbraten marked this conversation as resolved.
Show resolved
Hide resolved
|
||
id: number, | ||
namespace: string, | ||
name: string, | ||
path_with_namespace: string, // e.g. "mike/diaspora" | ||
git_http_url: string; // e.g. http://example.com/mike/diaspora.git | ||
web_url: string; // e.g. http://example.com/mike/diaspora | ||
visibility_level: number, | ||
avatar_url: string | null, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* Copyright (c) 2020 Gitpod GmbH. All rights reserved. | ||
* Licensed under the Gitpod Enterprise Source Code License, | ||
* See License.enterprise.txt in the project root folder. | ||
*/ | ||
|
||
import { RepositoryService } from "../../../src/repohost/repo-service"; | ||
import { inject, injectable } from "inversify"; | ||
import { GiteaRestApi } from "../../../src/gitea/api"; | ||
|
||
@injectable() | ||
export class GiteaService extends RepositoryService { | ||
@inject(GiteaRestApi) protected readonly giteaApi: GiteaRestApi; | ||
// TODO: complete? | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two tiny nitpicks, 1. It is possible for gitea to exist on a subpath (eg. https://example.com/gitea/ etc..), and 2. some users may wish not to use https (not a great idea, but one that people make for a variety of reasons).
You may wish instead of host, to use something like
baseURL
where users can fill the url scheme and full url (incl. a sub-path if they so require).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good points. I will have a look and do some tests later. Currently my main problem is still getting a Gitpod instance with those changes up and running. 🙈
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the issue a matter of compute resources available to you, or being able to apply your changes to a running deploy? If the former, the Gitea project likely can assist in providing compute resources, if the later I'm sure if you post the issue you are running into then someone can help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently using a cluster on vultr with with some credit I had lying around, so should be fine for the beginning, but I will come back to your offer if needed. Main problem is building images of the needed components and deploying those atm. It requires some manual intervention which loads to a pretty slow dev cycle as I have to rebuild the server, deploy it and look for changes ... The gitpod team seems to use telepresence for that, but I am not quite sure how to integrate that with my own cluster.