Skip to content

Commit

Permalink
Merge pull request #1347 from argos-ci/multiple-project-same-repo
Browse files Browse the repository at this point in the history
  • Loading branch information
gregberge authored Aug 13, 2024
2 parents b761315 + a52df3a commit 4725ca2
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 9 deletions.
83 changes: 83 additions & 0 deletions apps/backend/src/build-notification/notification.e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { invariant } from "@argos/util/invariant";
import { beforeEach, describe, expect, it } from "vitest";

import { Build } from "@/database/models/Build.js";
import { BuildNotification } from "@/database/models/BuildNotification.js";
import { factory } from "@/database/testing/index.js";
import { setupDatabase } from "@/database/testing/util.js";

import { getNotificationPayload } from "./notification.js";

describe("#getNotificationPayload", () => {
beforeEach(async () => {
await setupDatabase();
});

describe("with a repository only linked to one project", () => {
let build: Build;
let buildNotification: BuildNotification;

beforeEach(async () => {
const repository = await factory.GithubRepository.create();
const [project] = await factory.Project.createMany(2, [
{
githubRepositoryId: repository.id,
gitlabProjectId: null,
name: "backend",
},
{
githubRepositoryId: null,
gitlabProjectId: null,
name: "frontend",
},
]);
invariant(project);
build = await factory.Build.create({ projectId: project.id });
buildNotification = await factory.BuildNotification.create({
buildId: build.id,
});
});

it("returns argos as context", async () => {
const payload = await getNotificationPayload({
build,
buildNotification,
});
expect(payload.context).toBe("argos");
});
});

describe("with a GitHub repository linked to multiple projects", () => {
let build: Build;
let buildNotification: BuildNotification;

beforeEach(async () => {
const repository = await factory.GithubRepository.create();
const [project] = await factory.Project.createMany(2, [
{
githubRepositoryId: repository.id,
gitlabProjectId: null,
name: "backend",
},
{
githubRepositoryId: repository.id,
gitlabProjectId: null,
name: "frontend",
},
]);
invariant(project);
build = await factory.Build.create({ projectId: project.id });
buildNotification = await factory.BuildNotification.create({
buildId: build.id,
});
});

it("returns argos as context", async () => {
const payload = await getNotificationPayload({
build,
buildNotification,
});
expect(payload.context).toBe("argos/backend");
});
});
});
63 changes: 54 additions & 9 deletions apps/backend/src/build-notification/notification.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { assertNever } from "@argos/util/assertNever";
import { invariant } from "@argos/util/invariant";
import { z } from "zod";

import { getStatsMessage } from "@/build/stats.js";
import { Project } from "@/database/models";
import { Build } from "@/database/models/Build.js";
import type { BuildNotification } from "@/database/models/BuildNotification.js";
import { UnretryableError } from "@/job-core/error.js";
Expand All @@ -18,8 +20,48 @@ export const NotificationPayloadSchema = z.object({
});
export type NotificationPayload = z.infer<typeof NotificationPayloadSchema>;

function getStatusContext(buildName: string): string {
return buildName === "default" ? "argos" : `argos/${buildName}`;
/**
* Check if the project has a sibling project with the same repository.
*/
async function checkHasSiblingProject(project: Project): Promise<boolean> {
if (!project.githubRepositoryId && !project.gitlabProjectId) {
return false;
}

const query = Project.query();

if (project.githubRepositoryId) {
query.orWhere("githubRepositoryId", project.githubRepositoryId);
}

if (project.gitlabProjectId) {
query.orWhere("gitlabProjectId", project.gitlabProjectId);
}

const projectCount = await query.resultSize();
return projectCount > 1;
}

/**
* Get the status context for the build.
*/
async function getStatusContext(build: Build): Promise<string> {
let context = "argos";

await build.$fetchGraph("project", { skipFetched: true });
invariant(build.project, "Project not found", UnretryableError);

const hasSiblingProject = await checkHasSiblingProject(build.project);

if (hasSiblingProject) {
context = `${context}/${build.project.name}`;
}

if (build.name === "default") {
return context;
}

return `${context}/${build.name}`;
}

/**
Expand Down Expand Up @@ -135,18 +177,21 @@ async function getNotificationDescription(input: {
*/
export async function getNotificationPayload(input: {
buildNotification: Pick<BuildNotification, "type">;
build: Pick<Build, "id" | "name" | "type">;
build: Build;
}): Promise<NotificationPayload> {
const context = getStatusContext(input.build.name);
const [description, context] = await Promise.all([
getNotificationDescription({
buildNotificationType: input.buildNotification.type,
buildId: input.build.id,
isReference: input.build.type === "reference",
}),
getStatusContext(input.build),
]);
const states = getNotificationStates({
buildNotificationType: input.buildNotification.type,
isReference: input.build.type === "reference",
});
const description = await getNotificationDescription({
buildNotificationType: input.buildNotification.type,
buildId: input.build.id,
isReference: input.build.type === "reference",
});

return {
description,
context,
Expand Down

0 comments on commit 4725ca2

Please sign in to comment.