Skip to content

Commit e417576

Browse files
committed
GetConfigurationWebhookActivityStatus impl
1 parent d3f029e commit e417576

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

components/server/src/api/configuration-service-api.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
DeleteConfigurationRequest,
1616
DeleteConfigurationResponse,
1717
GetConfigurationRequest,
18+
GetConfigurationWebhookActivityStatusRequest,
19+
GetConfigurationWebhookActivityStatusResponse,
1820
ListConfigurationsRequest,
1921
ListConfigurationsResponse,
2022
PrebuildSettings,
@@ -30,6 +32,8 @@ import { SortOrder } from "@gitpod/public-api/lib/gitpod/v1/sorting_pb";
3032
import { Project } from "@gitpod/gitpod-protocol";
3133
import { DeepPartial } from "@gitpod/gitpod-protocol/lib/util/deep-partial";
3234
import { ContextService } from "../workspace/context-service";
35+
import { PrebuildManager } from "../prebuilds/prebuild-manager";
36+
import { Timestamp } from "@bufbuild/protobuf";
3337

3438
function buildUpdateObject<T extends Record<string, any>>(obj: T): Partial<T> {
3539
const update: Partial<T> = {};
@@ -58,6 +62,8 @@ export class ConfigurationServiceAPI implements ServiceImpl<typeof Configuration
5862
private readonly userService: UserService,
5963
@inject(ContextService)
6064
private readonly contextService: ContextService,
65+
@inject(PrebuildManager)
66+
private readonly prebuildManager: PrebuildManager,
6167
) {}
6268

6369
async createConfiguration(
@@ -238,4 +244,27 @@ export class ConfigurationServiceAPI implements ServiceImpl<typeof Configuration
238244

239245
return new DeleteConfigurationResponse();
240246
}
247+
248+
async getConfigurationWebhookActivityStatus(req: GetConfigurationWebhookActivityStatusRequest, _: HandlerContext) {
249+
if (!req.configurationId) {
250+
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "configuration_id is required");
251+
}
252+
253+
const configuration = await this.projectService.getProject(ctxUserId(), req.configurationId);
254+
if (!configuration) {
255+
throw new ApplicationError(ErrorCodes.NOT_FOUND, "configuration not found");
256+
}
257+
const user = await this.userService.findUserById(ctxUserId(), ctxUserId());
258+
const event = await this.prebuildManager.getRecentWebhookEvent({}, user, configuration);
259+
260+
const resp = new GetConfigurationWebhookActivityStatusResponse({
261+
isWebhookActive: event !== undefined,
262+
latestWebhookEvent: {
263+
commit: event?.commit,
264+
creationTime: event?.creationTime ? Timestamp.fromDate(new Date(event.creationTime)) : undefined,
265+
},
266+
});
267+
268+
return resp;
269+
}
241270
}

components/server/src/prebuilds/prebuild-manager.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { DBWithTracing, TracedWorkspaceDB, WorkspaceDB } from "@gitpod/gitpod-db/lib";
7+
import { DBWithTracing, TracedWorkspaceDB, WebhookEventDB, WorkspaceDB } from "@gitpod/gitpod-db/lib";
88
import {
99
CommitContext,
1010
CommitInfo,
@@ -16,6 +16,7 @@ import {
1616
StartPrebuildResult,
1717
TaskConfig,
1818
User,
19+
WebhookEvent,
1920
Workspace,
2021
WorkspaceConfig,
2122
WorkspaceInstance,
@@ -75,6 +76,7 @@ export class PrebuildManager {
7576
@inject(ContextParser) private contextParser: ContextParser,
7677
@inject(IAnalyticsWriter) private readonly analytics: IAnalyticsWriter,
7778
@inject(RedisSubscriber) private readonly subscriber: RedisSubscriber,
79+
@inject(WebhookEventDB) private readonly webhookEventDb: WebhookEventDB,
7880
) {}
7981

8082
private async findNonFailedPrebuiltWorkspace(ctx: TraceContext, projectId: string, commitSHA: string) {
@@ -115,6 +117,42 @@ export class PrebuildManager {
115117
}, opts);
116118
}
117119

120+
/**
121+
* getRecentWebhookEvent checks if the webhook integration is active for the given user and project by querying the webhook event database and seeing if for any of the latest n commits a webhook event exists.
122+
*/
123+
public async getRecentWebhookEvent(
124+
ctx: TraceContext,
125+
user: User,
126+
project: Project,
127+
): Promise<WebhookEvent | undefined> {
128+
const context = (await this.contextParser.handle(ctx, user, project.cloneUrl)) as CommitContext;
129+
const maxDepth = 15;
130+
131+
const events = await this.webhookEventDb.findByCloneUrl(project.cloneUrl, maxDepth);
132+
if (events.length === 0) {
133+
// return undefined;
134+
}
135+
136+
const hostContext = this.hostContextProvider.get(context.repository.host);
137+
const repoProvider = hostContext?.services?.repositoryProvider;
138+
if (!repoProvider) {
139+
throw new ApplicationError(ErrorCodes.INTERNAL_SERVER_ERROR, `repository provider not found`);
140+
}
141+
const history = await repoProvider.getCommitHistory(
142+
user,
143+
context.repository.owner,
144+
context.repository.name,
145+
context.revision,
146+
maxDepth,
147+
);
148+
if (!history) {
149+
throw new ApplicationError(ErrorCodes.NOT_FOUND, `commit history not found`);
150+
}
151+
const matchingEvent = events.find((event) => history.find((commit) => commit === event.commit));
152+
153+
return matchingEvent;
154+
}
155+
118156
public async *getAndWatchPrebuildStatus(
119157
userId: string,
120158
filter: {

0 commit comments

Comments
 (0)