Skip to content

Commit 3ec7952

Browse files
committed
enable prebuilds
1 parent cfa6e3d commit 3ec7952

File tree

10 files changed

+161
-28
lines changed

10 files changed

+161
-28
lines changed

components/dashboard/src/projects/Prebuild.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ import PrebuildLogs from "../components/PrebuildLogs";
1616
import { shortCommitMessage } from "./render-utils";
1717

1818
export default function () {
19-
const { teams } = useContext(TeamsContext);
2019
const location = useLocation();
20+
21+
const { teams } = useContext(TeamsContext);
22+
const team = getCurrentTeam(location, teams);
23+
2124
const match = useRouteMatch<{ team: string, project: string, prebuildId: string }>("/:team/:project/:prebuildId");
2225
const projectName = match?.params?.project;
2326
const prebuildId = match?.params?.prebuildId;
24-
const team = getCurrentTeam(location, teams);
2527

2628
const [ prebuild, setPrebuild ] = useState<PrebuildInfo | undefined>();
2729

@@ -44,7 +46,7 @@ export default function () {
4446
});
4547
setPrebuild(prebuilds[0]);
4648
})();
47-
}, [ teams, team ]);
49+
}, [ teams ]);
4850

4951
const renderTitle = () => {
5052
if (!prebuild) {

components/dashboard/src/projects/Prebuilds.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import { shortCommitMessage } from "./render-utils";
1818

1919
export default function () {
2020
const history = useHistory();
21-
const { teams } = useContext(TeamsContext);
2221
const location = useLocation();
22+
23+
const { teams } = useContext(TeamsContext);
24+
const team = getCurrentTeam(location, teams);
25+
2326
const match = useRouteMatch<{ team: string, resource: string }>("/:team/:resource");
2427
const projectName = match?.params?.resource;
25-
const team = getCurrentTeam(location, teams);
2628

2729
// @ts-ignore
2830
const [project, setProject] = useState<Project | undefined>();
@@ -55,7 +57,7 @@ export default function () {
5557
}
5658
}
5759
})();
58-
}, [ teams, team ]);
60+
}, [ teams ]);
5961

6062
const prebuildContextMenu = (p: PrebuildInfo) => {
6163
const running = p.status === "building";

components/dashboard/src/projects/Project.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import { shortCommitMessage } from "./render-utils";
1818

1919
export default function () {
2020
const history = useHistory();
21-
const { teams } = useContext(TeamsContext);
2221
const location = useLocation();
22+
23+
const { teams } = useContext(TeamsContext);
24+
const team = getCurrentTeam(location, teams);
25+
2326
const match = useRouteMatch<{ team: string, resource: string }>("/:team/:resource");
2427
const projectName = match?.params?.resource;
25-
const team = getCurrentTeam(location, teams);
2628

2729
const [project, setProject] = useState<Project | undefined>();
2830

@@ -34,7 +36,7 @@ export default function () {
3436

3537
useEffect(() => {
3638
updateProject();
37-
}, [ teams, team ]);
39+
}, [ teams ]);
3840

3941
const updateProject = async () => {
4042
if (!teams || !projectName) {
@@ -87,7 +89,7 @@ export default function () {
8789
// TODO(at): this need to be revised once prebuild events are integrated
8890
return;
8991
}
90-
if (!team || !project) {
92+
if (!project) {
9193
return;
9294
}
9395
prebuildLoaders.add(branch.name);

components/dashboard/src/projects/Projects.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default function () {
3232

3333
useEffect(() => {
3434
updateProjects();
35-
}, [ teams, team ]);
35+
}, [ teams ]);
3636

3737
const updateProjects = async () => {
3838
if (!teams) {

components/server/ee/src/gitlab/gitlab-app-support.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class GitLabAppSupport {
2727
// we are listing only those projects with access level of maintainers.
2828
// also cf. https://docs.gitlab.com/ee/api/members.html#valid-access-levels
2929
//
30-
const projectsWithAccess = await api.Projects.all({ min_access_level: "40" });
30+
const projectsWithAccess = await api.Projects.all({ min_access_level: "40", perPage: 100 });
3131
for (const project of projectsWithAccess) {
3232
const anyProject = project as any;
3333
const fullPath = anyProject.path_with_namespace as string;

components/server/ee/src/prebuilds/github-app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ export class GithubApp {
352352
}
353353
}
354354
}
355-
356355
}
356+
357357
protected async findInstallationOwner(installationId: number): Promise<{user: User, project?: Project} | undefined> {
358358
// Legacy mode
359359
//

components/server/ee/src/prebuilds/gitlab-app.ts

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
import * as express from 'express';
88
import { postConstruct, injectable, inject } from 'inversify';
9-
import { UserDB } from '@gitpod/gitpod-db/lib';
10-
import { User } from '@gitpod/gitpod-protocol';
9+
import { ProjectDB, TeamDB, UserDB } from '@gitpod/gitpod-db/lib';
10+
import { Project, User } from '@gitpod/gitpod-protocol';
1111
import { PrebuildManager } from '../prebuilds/prebuild-manager';
1212
import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing';
1313
import { StartPrebuildResult } from './prebuild-manager';
@@ -23,6 +23,8 @@ export class GitLabApp {
2323
@inject(PrebuildManager) protected readonly prebuildManager: PrebuildManager;
2424
@inject(TokenService) protected readonly tokenService: TokenService;
2525
@inject(HostContextProvider) protected readonly hostCtxProvider: HostContextProvider;
26+
@inject(ProjectDB) protected readonly projectDB: ProjectDB;
27+
@inject(TeamDB) protected readonly teamDB: TeamDB;
2628

2729
protected _router = express.Router();
2830
public static path = '/apps/gitlab/';
@@ -97,15 +99,35 @@ export class GitLabApp {
9799
}
98100

99101
log.debug({ userId: user.id }, "GitLab push hook: Starting prebuild", { body, contextURL });
100-
// todo@alex: add branch and project args
101-
const ws = await this.prebuildManager.startPrebuild({ span }, { user, contextURL, cloneURL: body.repository.git_http_url, commit: body.after });
102+
103+
const branch = this.getBranchFromRef(body.ref);
104+
const project = (await this.findProjectOwner(body.repository.git_http_url))?.project;
105+
106+
const ws = await this.prebuildManager.startPrebuild({ span }, { user, contextURL, cloneURL: body.repository.git_http_url, commit: body.after, branch, project });
102107

103108
return ws;
104109
} finally {
105110
span.finish();
106111
}
107112
}
108113

114+
protected async findProjectOwner(cloneURL: string): Promise<{user: User, project?: Project} | undefined> {
115+
// Project mode
116+
//
117+
const project = await this.projectDB.findProjectByCloneUrl(cloneURL);
118+
if (project) {
119+
const owner = !!project.userId
120+
? { userId: project.userId }
121+
: (await this.teamDB.findMembersByTeam(project.teamId || '')).filter(m => m.role === "owner")[0];
122+
if (owner) {
123+
const user = await this.userDB.findUserById(owner.userId);
124+
if (user) {
125+
return { user, project};
126+
}
127+
}
128+
}
129+
}
130+
109131
protected createContextUrl(body: GitLabPushHook) {
110132
const repoUrl = body.repository.git_http_url;
111133
const contextURL = `${repoUrl.substr(0, repoUrl.length - 4)}/-/tree${body.ref.substr('refs/head/'.length)}`;
@@ -115,16 +137,41 @@ export class GitLabApp {
115137
get router(): express.Router {
116138
return this._router;
117139
}
140+
141+
protected getBranchFromRef(ref: string): string | undefined {
142+
const headsPrefix = "refs/heads/";
143+
if (ref.startsWith(headsPrefix)) {
144+
return ref.substring(headsPrefix.length);
145+
}
146+
147+
return undefined;
148+
}
118149
}
119150

120151
interface GitLabPushHook {
121152
object_kind: 'push';
122153
before: string;
123154
after: string; // commit
124-
ref: string; // branch
155+
ref: string; // e.g. "refs/heads/master"
156+
user_avatar: string;
157+
user_name: string;
158+
project: GitLabProject;
125159
repository: GitLabRepository;
126160
}
127161

128162
interface GitLabRepository {
129-
git_http_url: string; //e.g. http://example.com/mike/diaspora.git
163+
name: string,
164+
git_http_url: string; // e.g. http://example.com/mike/diaspora.git
165+
visibility_level: number,
166+
}
167+
168+
interface GitLabProject {
169+
id: number,
170+
namespace: string,
171+
name: string,
172+
path_with_namespace: string, // e.g. "mike/diaspora"
173+
git_http_url: string; // e.g. http://example.com/mike/diaspora.git
174+
web_url: string; // e.g. http://example.com/mike/diaspora
175+
visibility_level: number,
176+
avatar_url: string | null,
130177
}

components/server/src/gitlab/api.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,15 @@ export namespace GitLab {
225225
short_id: string;
226226
title: string;
227227
message: string;
228-
parent_ids: string[];
228+
parent_ids: string[] | null;
229+
author_name: string;
230+
authored_date: string;
229231
}
230232
export interface Branch {
231233
commit: Commit;
232234
name: string;
233235
default: boolean;
236+
web_url: string;
234237
}
235238
export interface Tag {
236239
name: string,

components/server/src/gitlab/gitlab-repository-provider.ts

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { GitLabApi, GitLab } from "./api";
1111
import { RepositoryProvider } from '../repohost/repository-provider';
1212
import { parseRepoUrl } from '../repohost/repo-url';
1313

14+
import { log } from '@gitpod/gitpod-protocol/lib/util/logging';
15+
1416
@injectable()
1517
export class GitlabRepositoryProvider implements RepositoryProvider {
1618
@inject(GitLabApi) protected readonly gitlab: GitLabApi;
@@ -31,17 +33,64 @@ export class GitlabRepositoryProvider implements RepositoryProvider {
3133
}
3234

3335
async getBranch(user: User, owner: string, repo: string, branch: string): Promise<Branch> {
34-
// todo
35-
throw new Error("not implemented");
36+
const response = await this.gitlab.run<GitLab.Branch>(user, async g => {
37+
return g.Branches.show(`${owner}/${repo}`, branch);
38+
});
39+
if (GitLab.ApiError.is(response)) {
40+
throw response;
41+
}
42+
return {
43+
htmlUrl: response.web_url,
44+
name: response.name,
45+
commit: {
46+
sha: response.commit.id,
47+
author: response.commit.author_name,
48+
authorDate: response.commit.authored_date,
49+
commitMessage: "UNKNOWN COMMIT MESSAGE",
50+
authorAvatarUrl: "",
51+
}
52+
};
3653
}
3754

3855
async getBranches(user: User, owner: string, repo: string): Promise<Branch[]> {
39-
// todo
40-
return [];
56+
const branches: Branch[] = [];
57+
const response = await this.gitlab.run<GitLab.Branch[]>(user, async g => {
58+
return g.Branches.all(`${owner}/${repo}`);
59+
});
60+
if (GitLab.ApiError.is(response)) {
61+
throw response;
62+
}
63+
for (const b of response) {
64+
branches.push({
65+
htmlUrl: b.web_url,
66+
name: b.name,
67+
commit: {
68+
sha: b.commit.id,
69+
author: b.commit.author_name,
70+
authorDate: b.commit.authored_date,
71+
commitMessage: "UNKNOWN COMMIT MESSAGE",
72+
authorAvatarUrl: "",
73+
}
74+
})
75+
}
76+
return branches;
4177
}
4278

4379
async getCommitInfo(user: User, owner: string, repo: string, ref: string): Promise<CommitInfo | undefined> {
44-
// todo
45-
return undefined;
80+
const response = await this.gitlab.run<GitLab.Commit>(user, async g => {
81+
return g.Commits.show(`${owner}/${repo}`, ref);
82+
});
83+
if (GitLab.ApiError.is(response)) {
84+
// throw response;
85+
log.debug("Failed to fetch commit.", { response });
86+
return undefined;
87+
}
88+
return {
89+
sha: response.id,
90+
author: response.author_name,
91+
authorDate: response.authored_date,
92+
commitMessage: "UNKNOWN COMMIT MESSAGE",
93+
authorAvatarUrl: "",
94+
};
4695
}
4796
}

components/server/src/projects/projects-service.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import { inject, injectable } from "inversify";
8-
import { DBWithTracing, ProjectDB, TeamDB, TracedWorkspaceDB, WorkspaceDB } from "@gitpod/gitpod-db/lib";
8+
import { DBWithTracing, ProjectDB, TeamDB, TracedWorkspaceDB, UserDB, WorkspaceDB } from "@gitpod/gitpod-db/lib";
99
import { Branch, CommitInfo, CreateProjectParams, FindPrebuildsParams, PrebuildInfo, PrebuiltWorkspace, Project, ProjectConfig, User } from "@gitpod/gitpod-protocol";
1010
import { HostContextProvider } from "../auth/host-context-provider";
1111
import { parseRepoUrl } from "../repohost";
@@ -16,6 +16,7 @@ export class ProjectsService {
1616

1717
@inject(ProjectDB) protected readonly projectDB: ProjectDB;
1818
@inject(TeamDB) protected readonly teamDB: TeamDB;
19+
@inject(UserDB) protected readonly userDB: UserDB;
1920
@inject(TracedWorkspaceDB) protected readonly workspaceDb: DBWithTracing<WorkspaceDB>;
2021
@inject(HostContextProvider) protected readonly hostContextProvider: HostContextProvider;
2122

@@ -92,7 +93,34 @@ export class ProjectsService {
9293
...(!!userId ? { userId } : { teamId }),
9394
appInstallationId
9495
});
95-
return this.projectDB.storeProject(project);
96+
await this.projectDB.storeProject(project);
97+
98+
// TODO(at) refactor
99+
100+
const parsedUrl = parseRepoUrl(project.cloneUrl);
101+
if ("gitlab.com" === parsedUrl?.host) {
102+
const repositoryService = this.hostContextProvider.get(parsedUrl?.host)?.services?.repositoryService;
103+
if (repositoryService) {
104+
let user: User | undefined;
105+
if (userId) {
106+
user = await this.userDB.findUserById(userId);
107+
} else if (teamId) {
108+
const owner = await (await this.teamDB.findMembersByTeam(teamId)).find(m => m.role === "owner");
109+
if (owner) {
110+
user = await this.userDB.findUserById(owner.userId);
111+
}
112+
}
113+
if (user) {
114+
if (await repositoryService.canInstallAutomatedPrebuilds(user, cloneUrl)) {
115+
await repositoryService.installAutomatedPrebuilds(user, cloneUrl);
116+
}
117+
} else {
118+
log.error("cannot find user for project", { cloneUrl })
119+
}
120+
}
121+
}
122+
123+
return project;
96124
}
97125

98126
async deleteProject(projectId: string): Promise<void> {

0 commit comments

Comments
 (0)