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

Prebuild Events #5116

Merged
merged 3 commits into from
Sep 1, 2021
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
14 changes: 7 additions & 7 deletions components/dashboard/src/projects/Prebuild.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import moment from "moment";
import { PrebuildInfo } from "@gitpod/gitpod-protocol";
import { PrebuildWithStatus } from "@gitpod/gitpod-protocol";
import { useContext, useEffect, useState } from "react";
import { useLocation, useRouteMatch } from "react-router";
import Header from "../components/Header";
Expand All @@ -25,7 +25,7 @@ export default function () {
const projectName = match?.params?.project;
const prebuildId = match?.params?.prebuildId;

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

useEffect(() => {
if (!teams || !projectName || !prebuildId) {
Expand All @@ -52,7 +52,7 @@ export default function () {
if (!prebuild) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did get to see a Prebuild with working logs, but for another Prebuild (for https://gitlab.com/gitpod-io/gitlab/-/merge_requests/1) I got this slightly worrying error:

Uncaught (in promise) Error: Request findPrebuilds failed with message: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1

Screenshot 2021-08-25 at 10 57 11

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jankeromnes, I've add a check to prevent it from hitting the db layer: https://github.com/gitpod-io/gitpod/pull/5116/files#diff-9c81815b0337b4e00a2ab1615cab6010a2497412f99dfc63c73a17f8bf28a90cR877

Can you invite me to that team please? I'd like to reproduce/verify the fix

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's on my user 😬 but please feel free to move it to a team by hacking the DB

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexTugarev I tried reproducing this bug, but I couldn't. Maybe that's a somewhat good sign? Although quite inconclusive, due to the problems on dev-staging / the partial deployment. 😅

  • I tried triggering new prebuilds, but they get lost in the "randomly-sorted 30-limited Prebuilds list" (the current deployment probably doesn't have the sort-order or creationTime fixes)

Screenshot 2021-08-26 at 11 45 23

Screenshot 2021-08-26 at 11 59 49

return "unknown prebuild";
}
return (<h1 className="tracking-tight">{prebuild.branch} </h1>);
return (<h1 className="tracking-tight">{prebuild.info.branch} </h1>);
};

const renderSubtitle = () => {
Expand All @@ -61,19 +61,19 @@ export default function () {
}
const statusIcon = prebuildStatusIcon(prebuild.status);
const status = prebuildStatusLabel(prebuild.status);
const startedByAvatar = prebuild.startedByAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={prebuild.startedByAvatar || ''} alt={prebuild.startedBy} />;
const startedByAvatar = prebuild.info.startedByAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={prebuild.info.startedByAvatar || ''} alt={prebuild.info.startedBy} />;
return (<div className="flex">
<div className="text-base text-gray-900 dark:text-gray-50 font-medium uppercase">
<div className="inline-block align-text-bottom mr-2 w-4 h-4">{statusIcon}</div>
{status}
</div>
<p className="mx-2 my-auto">·</p>
<div className="my-auto">
<p>{startedByAvatar}Triggered {moment(prebuild.startedAt).fromNow()}</p>
<p>{startedByAvatar}Triggered {moment(prebuild.info.startedAt).fromNow()}</p>
</div>
<p className="mx-2 my-auto">·</p>
<div className="my-auto">
<p className="text-gray-500 dark:text-gray-50">{shortCommitMessage(prebuild.changeTitle)}</p>
<p className="text-gray-500 dark:text-gray-50">{shortCommitMessage(prebuild.info.changeTitle)}</p>
</div>
</div>)
};
Expand All @@ -84,7 +84,7 @@ export default function () {
<Header title={renderTitle()} subtitle={renderSubtitle()} />
<div className="lg:px-28 px-10 mt-8">
<div className="h-96 rounded-xl overflow-hidden bg-gray-100 dark:bg-gray-800 flex flex-col">
<PrebuildLogs workspaceId={prebuild?.buildWorkspaceId}/>
<PrebuildLogs workspaceId={prebuild?.info?.buildWorkspaceId}/>
</div>
</div>
</>;
Expand Down
66 changes: 40 additions & 26 deletions components/dashboard/src/projects/Prebuilds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import moment from "moment";
import { PrebuildInfo, PrebuiltWorkspaceState, Project } from "@gitpod/gitpod-protocol";
import { PrebuildInfo, PrebuildWithStatus, PrebuiltWorkspaceState, Project } from "@gitpod/gitpod-protocol";
import { useContext, useEffect, useState } from "react";
import { useHistory, useLocation, useRouteMatch } from "react-router";
import Header from "../components/Header";
Expand All @@ -26,14 +26,33 @@ export default function () {
const match = useRouteMatch<{ team: string, resource: string }>("/:team/:resource");
const projectName = match?.params?.resource;

// @ts-ignore
const [project, setProject] = useState<Project | undefined>();
const [defaultBranch, setDefaultBranch] = useState<string | undefined>();

const [searchFilter, setSearchFilter] = useState<string | undefined>();
const [statusFilter, setStatusFilter] = useState<PrebuiltWorkspaceState | undefined>();

const [prebuilds, setPrebuilds] = useState<PrebuildInfo[]>([]);
const [prebuilds, setPrebuilds] = useState<PrebuildWithStatus[]>([]);

useEffect(() => {
if (!project) {
return;
}
const registration = getGitpodService().registerClient({
onPrebuildUpdate: (update: PrebuildWithStatus) => {
setPrebuilds(prev => [update, ...prev.filter(p => p.info.id !== update.info.id)])
}
});

(async () => {
const prebuilds = await getGitpodService().server.findPrebuilds({ projectId: project.id });
setPrebuilds(prebuilds);
})();
AlexTugarev marked this conversation as resolved.
Show resolved Hide resolved

return () => {
registration.dispose();
}
}, [project]);

useEffect(() => {
if (!teams) {
Expand All @@ -44,31 +63,28 @@ export default function () {
? await getGitpodService().server.getTeamProjects(team.id)
: await getGitpodService().server.getUserProjects());

const project = projectName && projects.find(p => p.name === projectName);
if (project) {
setProject(project);

const prebuilds = await getGitpodService().server.findPrebuilds({ projectId: project.id });
setPrebuilds(prebuilds);
const newProject = projectName && projects.find(p => p.name === projectName);
if (newProject) {
setProject(newProject);

const details = await getGitpodService().server.getProjectOverview(project.id);
const details = await getGitpodService().server.getProjectOverview(newProject.id);
if (details?.branches) {
setDefaultBranch(details.branches.find(b => b.isDefault)?.name);
}
}
})();
}, [ teams ]);
}, [teams]);

const prebuildContextMenu = (p: PrebuildInfo) => {
const prebuildContextMenu = (p: PrebuildWithStatus) => {
const running = p.status === "building";
const entries: ContextMenuEntry[] = [];
entries.push({
title: "View Prebuild",
onClick: () => openPrebuild(p)
onClick: () => openPrebuild(p.info)
});
entries.push({
title: "Trigger Prebuild",
onClick: () => triggerPrebuild(p.branch),
onClick: () => triggerPrebuild(p.info.branch),
separator: running
});
if (running) {
Expand All @@ -94,18 +110,16 @@ export default function () {
return entries;
}

const filter = (p: PrebuildInfo) => {
const filter = (p: PrebuildWithStatus) => {
if (statusFilter && statusFilter !== p.status) {
return false;
}
if (searchFilter && `${p.changeTitle} ${p.branch}`.toLowerCase().includes(searchFilter.toLowerCase()) === false) {
if (searchFilter && `${p.info.changeTitle} ${p.info.branch}`.toLowerCase().includes(searchFilter.toLowerCase()) === false) {
return false;
}
return true;
}

const filteredPrebuilds = prebuilds.filter(filter);

const openPrebuild = (pb: PrebuildInfo) => {
history.push(`/${!!team ? team.slug : 'projects'}/${projectName}/${pb.id}`);
}
Expand Down Expand Up @@ -149,25 +163,25 @@ export default function () {
<ItemFieldContextMenu />
</ItemField>
</Item>
{filteredPrebuilds.map((p: PrebuildInfo) => <Item className="grid grid-cols-3">
{prebuilds.filter(filter).map((p, index) => <Item key={`prebuild-${p.info.id}`} className="grid grid-cols-3">
<ItemField className="flex items-center">
<div className="cursor-pointer" onClick={() => openPrebuild(p)}>
<div className="cursor-pointer" onClick={() => openPrebuild(p.info)}>
<div className="text-base text-gray-900 dark:text-gray-50 font-medium uppercase mb-1">
<div className="inline-block align-text-bottom mr-2 w-4 h-4">{prebuildStatusIcon(p.status)}</div>
{prebuildStatusLabel(p.status)}
</div>
<p>{p.startedByAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={p.startedByAvatar || ''} alt={p.startedBy} />}Triggered {formatDate(p.startedAt)}</p>
<p>{p.info.startedByAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={p.info.startedByAvatar || ''} alt={p.info.startedBy} />}Triggered {formatDate(p.info.startedAt)}</p>
</div>
</ItemField>
<ItemField className="flex items-center">
<div>
<div className="text-base text-gray-500 dark:text-gray-50 font-medium mb-1">{shortCommitMessage(p.changeTitle)}</div>
<p>{p.changeAuthorAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={p.changeAuthorAvatar || ''} alt={p.changeAuthor} />}Authored {formatDate(p.changeDate)} · {p.changeHash?.substring(0, 8)}</p>
<div className="text-base text-gray-500 dark:text-gray-50 font-medium mb-1">{shortCommitMessage(p.info.changeTitle)}</div>
<p>{p.info.changeAuthorAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={p.info.changeAuthorAvatar || ''} alt={p.info.changeAuthor} />}Authored {formatDate(p.info.changeDate)} · {p.info.changeHash?.substring(0, 8)}</p>
</div>
</ItemField>
<ItemField className="flex items-center">
<div className="flex space-x-2">
<span className="font-medium text-gray-500 dark:text-gray-50">{p.branch}</span>
<span className="font-medium text-gray-500 dark:text-gray-50">{p.info.branch}</span>
</div>
<span className="flex-grow" />
<ItemFieldContextMenu menuEntries={prebuildContextMenu(p)} />
Expand All @@ -179,7 +193,7 @@ export default function () {
</>;
}

export function prebuildStatusLabel(status: PrebuiltWorkspaceState) {
export function prebuildStatusLabel(status: PrebuiltWorkspaceState | undefined) {
switch (status) {
case "aborted":
return (<span className="font-medium text-red-500 uppercase">failed</span>);
Expand All @@ -193,7 +207,7 @@ export function prebuildStatusLabel(status: PrebuiltWorkspaceState) {
break;
}
}
export function prebuildStatusIcon(status: PrebuiltWorkspaceState) {
export function prebuildStatusIcon(status: PrebuiltWorkspaceState | undefined) {
switch (status) {
case "aborted":
return (<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down
10 changes: 5 additions & 5 deletions components/dashboard/src/projects/Project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import moment from "moment";
import { PrebuildInfo, Project } from "@gitpod/gitpod-protocol";
import { PrebuildInfo, PrebuildWithStatus, Project } from "@gitpod/gitpod-protocol";
import { useContext, useEffect, useState } from "react";
import { useHistory, useLocation, useRouteMatch } from "react-router";
import Header from "../components/Header";
Expand All @@ -29,7 +29,7 @@ export default function () {
const [project, setProject] = useState<Project | undefined>();

const [branches, setBranches] = useState<Project.BranchDetails[]>([]);
const [lastPrebuilds, setLastPrebuilds] = useState<Map<string, PrebuildInfo | undefined>>(new Map());
const [lastPrebuilds, setLastPrebuilds] = useState<Map<string, PrebuildWithStatus | undefined>>(new Map());
const [prebuildLoaders] = useState<Set<string>>(new Set());

const [searchFilter, setSearchFilter] = useState<string | undefined>();
Expand Down Expand Up @@ -160,8 +160,8 @@ export default function () {
const prebuild = lastPrebuild(branch); // this might lazily trigger fetching of prebuild details

const avatar = branch.changeAuthorAvatar && <img className="rounded-full w-4 h-4 inline-block align-text-bottom mr-2" src={branch.changeAuthorAvatar || ''} alt={branch.changeAuthor} />;
const statusIcon = prebuild?.status && prebuildStatusIcon(prebuild.status);
const status = prebuild?.status && prebuildStatusLabel(prebuild.status);
const statusIcon = prebuildStatusIcon(prebuild?.status);
const status = prebuildStatusLabel(prebuild?.status);

return <Item key={`branch-${index}-${branchName}`} className="grid grid-cols-3 group">
<ItemField className="flex items-center">
Expand All @@ -179,7 +179,7 @@ export default function () {
</div>
</ItemField>
<ItemField className="flex items-center">
<div className="text-base text-gray-900 dark:text-gray-50 font-medium uppercase mb-1 cursor-pointer" onClick={() => prebuild && openPrebuild(prebuild)}>
<div className="text-base text-gray-900 dark:text-gray-50 font-medium uppercase mb-1 cursor-pointer" onClick={() => prebuild && openPrebuild(prebuild.info)}>
{prebuild ? (<><div className="inline-block align-text-bottom mr-2 w-4 h-4">{statusIcon}</div>{status}</>) : (<span> </span>)}
</div>
<span className="flex-grow" />
Expand Down
10 changes: 5 additions & 5 deletions components/dashboard/src/projects/Projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useContext, useEffect, useState } from "react";
import { getGitpodService } from "../service/service";
import { getCurrentTeam, TeamsContext } from "../teams/teams-context";
import { ThemeContext } from "../theme-context";
import { PrebuildInfo, PrebuiltWorkspaceState, Project } from "@gitpod/gitpod-protocol";
import { PrebuildWithStatus, PrebuiltWorkspaceState, Project } from "@gitpod/gitpod-protocol";
import { toRemoteURL } from "./render-utils";
import ContextMenu from "../components/ContextMenu";
import StatusDone from "../icons/StatusDone.svg";
Expand All @@ -29,7 +29,7 @@ export default function () {
const { teams } = useContext(TeamsContext);
const team = getCurrentTeam(location, teams);
const [ projects, setProjects ] = useState<Project[]>([]);
const [ lastPrebuilds, setLastPrebuilds ] = useState<Map<string, PrebuildInfo>>(new Map());
const [ lastPrebuilds, setLastPrebuilds ] = useState<Map<string, PrebuildWithStatus>>(new Map());

const { isDark } = useContext(ThemeContext);

Expand Down Expand Up @@ -160,11 +160,11 @@ export default function () {
<div className="h-10 px-4 border rounded-b-xl dark:border-gray-800 bg-gray-100 border-gray-100 dark:bg-gray-800">
{lastPrebuilds.get(p.id)
? (<div className="flex flex-row h-full text-sm justify-between">
<Link to={`/${teamOrUserSlug}/${p.name}/${lastPrebuilds.get(p.id)!.id}`} className="flex my-auto group space-x-2">
<Link to={`/${teamOrUserSlug}/${p.name}/${lastPrebuilds.get(p.id)?.info?.id}`} className="flex my-auto group space-x-2">
<img className="h-4 w-4 my-auto" src={getPrebuildStatusIcon(lastPrebuilds.get(p.id)!.status)} />
<div className="my-auto font-semibold text-gray-500 dark:text-gray-400 truncate w-24" title={lastPrebuilds.get(p.id)!.branch}>{lastPrebuilds.get(p.id)!.branch}</div>
<div className="my-auto font-semibold text-gray-500 dark:text-gray-400 truncate w-24" title={lastPrebuilds.get(p.id)?.info?.branch}>{lastPrebuilds.get(p.id)?.info?.branch}</div>
<span className="mx-1 my-auto text-gray-400 dark:text-gray-600">·</span>
<div className="my-auto text-gray-400 dark:text-gray-500 flex-grow hover:text-gray-800 dark:hover:text-gray-300">{moment(lastPrebuilds.get(p.id)!.startedAt, "YYYYMMDD").fromNow()}</div>
<div className="my-auto text-gray-400 dark:text-gray-500 flex-grow hover:text-gray-800 dark:hover:text-gray-300">{moment(lastPrebuilds.get(p.id)?.info?.startedAt, "YYYYMMDD").fromNow()}</div>
</Link>
<Link to={`/${teamOrUserSlug}/${p.name}/prebuilds`} className="my-auto group">
<div className="flex my-auto text-gray-400 flex-grow text-right group-hover:text-gray-600 dark:hover:text-gray-300">View All &rarr;</div>
Expand Down
74 changes: 38 additions & 36 deletions components/dashboard/src/service/service-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,43 +106,45 @@ const gitpodServiceMock = createServiceMock({
findPrebuilds: async (p) => {
const { projectId } = p;
return [{
id: "pb1",
branch: "main",
buildWorkspaceId: "123",
teamId: "t1",
projectId,
projectName: "pb1",
cloneUrl: pr1.cloneUrl,
startedAt: t1,
startedBy: u1.id,
startedByAvatar: u1.avatarUrl,
status: "available",
changeTitle: "[Comp] Add new functionality for",
changeDate: t1,
changeAuthor: u1.fullName!,
changeAuthorAvatar: u1.avatarUrl,
changePR: "4647",
changeUrl: "https://github.com/gitpod-io/gitpod/pull/4738",
changeHash: "2C0FFE"
info: {
id: "pb1",
branch: "main",
buildWorkspaceId: "123",
teamId: "t1",
projectId,
projectName: "pb1",
cloneUrl: pr1.cloneUrl,
startedAt: t1,
startedBy: u1.id,
startedByAvatar: u1.avatarUrl,
changeTitle: "[Comp] Add new functionality for",
changeDate: t1,
changeAuthor: u1.fullName!,
changeAuthorAvatar: u1.avatarUrl,
changePR: "4647",
changeUrl: "https://github.com/gitpod-io/gitpod/pull/4738",
changeHash: "2C0FFE"
}, status: "available"
}, {
id: "pb1",
branch: "foo/bar",
buildWorkspaceId: "1234",
teamId: "t1",
projectId,
projectName: "pb1",
cloneUrl: pr1.cloneUrl,
startedAt: t1,
startedBy: u1.id,
startedByAvatar: u1.avatarUrl,
status: "aborted",
changeTitle: "Fix Bug Nr 1",
changeDate: t1,
changeAuthor: u1.fullName!,
changeAuthorAvatar: u1.avatarUrl,
changePR: "4245",
changeUrl: "https://github.com/gitpod-io/gitpod/pull/4738",
changeHash: "1C0FFE"
info: {
id: "pb1",
branch: "foo/bar",
buildWorkspaceId: "1234",
teamId: "t1",
projectId,
projectName: "pb1",
cloneUrl: pr1.cloneUrl,
startedAt: t1,
startedBy: u1.id,
startedByAvatar: u1.avatarUrl,
changeTitle: "Fix Bug Nr 1",
changeDate: t1,
changeAuthor: u1.fullName!,
changeAuthorAvatar: u1.avatarUrl,
changePR: "4245",
changeUrl: "https://github.com/gitpod-io/gitpod/pull/4738",
changeHash: "1C0FFE"
}, status: "available"
}
]
},
Expand Down
Loading