Use query builder to get projects without deployments
All checks were successful
Lint / lint (20.x) (pull_request) Successful in 4m13s

This commit is contained in:
IshaVenikar 2024-10-21 10:07:34 +05:30
parent 1bd28e0309
commit 83819fc211
8 changed files with 120 additions and 128 deletions

View File

@ -150,6 +150,19 @@ export class Database {
return project; return project;
} }
async allProjectsWithoutDeployments(): Promise<Project[]> {
const projectRepository = this.dataSource.getRepository(Project);
const projects = await projectRepository
.createQueryBuilder('project')
.leftJoinAndSelect('project.deployments', 'deployment', 'deployment.deletedAt IS NULL') // Join only non-soft-deleted deployments
.where('deployment.id IS NULL') // Get projects where no deployments are present
.andWhere('project.auctionId IS NOT NULL') // Ensure auctionId is not null
.getMany();
return projects;
}
async getProjectsInOrganization( async getProjectsInOrganization(
userId: string, userId: string,
organizationSlug: string organizationSlug: string

View File

@ -417,13 +417,7 @@ export class Registry {
} }
async getCompletedAuctionIds(auctionIds: string[]): Promise<string[]> { async getCompletedAuctionIds(auctionIds: string[]): Promise<string[]> {
const validAuctionIds = auctionIds.filter((id): id is string => id !== ''); const auctions = await this.registry.getAuctionsByIds(auctionIds);
if (!validAuctionIds.length) {
return [];
}
const auctions = await this.registry.getAuctionsByIds(validAuctionIds);
const completedAuctions = auctions const completedAuctions = auctions
.filter((auction: { id: string, status: string }) => auction.status === 'completed') .filter((auction: { id: string, status: string }) => auction.status === 'completed')

View File

@ -6,7 +6,7 @@ import { Permission } from './entity/ProjectMember';
import { Domain } from './entity/Domain'; import { Domain } from './entity/Domain';
import { Project } from './entity/Project'; import { Project } from './entity/Project';
import { EnvironmentVariable } from './entity/EnvironmentVariable'; import { EnvironmentVariable } from './entity/EnvironmentVariable';
import { AddProjectFromTemplateInput, AuctionParams } from './types'; import { AddProjectFromTemplateInput, AuctionParams, EnvironmentVariables } from './types';
const log = debug('snowball:resolver'); const log = debug('snowball:resolver');
@ -218,7 +218,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
data: AddProjectFromTemplateInput; data: AddProjectFromTemplateInput;
lrn: string; lrn: string;
auctionParams: AuctionParams, auctionParams: AuctionParams,
environmentVariables: { environments: string[]; key: string; value: string }[]; environmentVariables: EnvironmentVariables[];
}, },
context: any, context: any,
) => { ) => {
@ -250,7 +250,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
data: DeepPartial<Project>; data: DeepPartial<Project>;
lrn: string; lrn: string;
auctionParams: AuctionParams, auctionParams: AuctionParams,
environmentVariables: { environments: string[]; key: string; value: string }[]; environmentVariables: EnvironmentVariables[];
}, },
context: any, context: any,
) => { ) => {

View File

@ -20,6 +20,7 @@ import {
AppDeploymentRecord, AppDeploymentRecord,
AppDeploymentRemovalRecord, AppDeploymentRemovalRecord,
AuctionParams, AuctionParams,
EnvironmentVariables,
GitPushEventPayload, GitPushEventPayload,
} from './types'; } from './types';
import { Role } from './entity/UserOrganization'; import { Role } from './entity/UserOrganization';
@ -167,7 +168,7 @@ export class Service {
async updateDeploymentsWithRecordData( async updateDeploymentsWithRecordData(
records: AppDeploymentRecord[], records: AppDeploymentRecord[],
): Promise<void> { ): Promise<void> {
// get and update deployments to be updated using request id // Fetch the deployments to be updated using deployment requestId
const deployments = await this.db.getDeployments({ const deployments = await this.db.getDeployments({
where: records.map((record) => ({ where: records.map((record) => ({
applicationDeploymentRequestId: record.attributes.request, applicationDeploymentRequestId: record.attributes.request,
@ -220,10 +221,10 @@ export class Service {
await Promise.all(deploymentUpdatePromises); await Promise.all(deploymentUpdatePromises);
// if iscurrent is true for this deployment then update the old ones // Get deployments that are in production environment
const prodDeployments = Object.values(recordToDeploymentsMap).filter(deployment => deployment.isCurrent); const prodDeployments = Object.values(recordToDeploymentsMap).filter(deployment => deployment.isCurrent);
// Get deployment IDs of deployments that are in production environment // Set the isCurrent state to false for the old deployments
for (const deployment of prodDeployments) { for (const deployment of prodDeployments) {
const projectDeployments = await this.db.getDeploymentsByProjectId(deployment.projectId); const projectDeployments = await this.db.getDeploymentsByProjectId(deployment.projectId);
const oldDeployments = projectDeployments const oldDeployments = projectDeployments
@ -236,15 +237,6 @@ export class Service {
} }
} }
// Get old deployments for ApplicationDeploymentRecords
// flter out deps with is current false
// loop over these deps
// get the project
// get all the deployemnts in that proj with the same deployer lrn (query filter not above updated dep)
// set is current to false
await Promise.all(deploymentUpdatePromises); await Promise.all(deploymentUpdatePromises);
} }
@ -298,24 +290,12 @@ export class Service {
* Calls the createDeploymentFromAuction method for deployments with completed auctions * Calls the createDeploymentFromAuction method for deployments with completed auctions
*/ */
async checkAuctionStatus(): Promise<void> { async checkAuctionStatus(): Promise<void> {
const allProjects = await this.db.getProjects({ const projects = await this.db.allProjectsWithoutDeployments();
where: {
auctionId: Not(IsNull()),
},
relations: ['deployments'],
withDeleted: true,
});
// Should only check on the first deployment const validAuctionIds = projects.map((project) => project.auctionId!)
const projects = allProjects.filter(project => { .filter((id): id is string => Boolean(id));
if (project.deletedAt !== null) return false; const completedAuctionIds = await this.laconicRegistry.getCompletedAuctionIds(validAuctionIds);
return project.deployments.length === 0;
});
if (projects.length > 0) {
const auctionIds = projects.map((project) => project.auctionId!);
const completedAuctionIds = await this.laconicRegistry.getCompletedAuctionIds(auctionIds);
const projectsToBedeployed = projects.filter((project) => const projectsToBedeployed = projects.filter((project) =>
completedAuctionIds.includes(project.auctionId!) completedAuctionIds.includes(project.auctionId!)
); );
@ -337,7 +317,6 @@ export class Service {
} }
} }
} }
}
this.auctionStatusCheckTimeout = setTimeout(() => { this.auctionStatusCheckTimeout = setTimeout(() => {
this.checkAuctionStatus(); this.checkAuctionStatus();
@ -785,7 +764,7 @@ export class Service {
data: AddProjectFromTemplateInput, data: AddProjectFromTemplateInput,
lrn?: string, lrn?: string,
auctionParams?: AuctionParams, auctionParams?: AuctionParams,
environmentVariables?: { environments: string[]; key: string; value: string }[], environmentVariables?: EnvironmentVariables[],
): Promise<Project | undefined> { ): Promise<Project | undefined> {
try { try {
const octokit = await this.getOctokit(user.id); const octokit = await this.getOctokit(user.id);
@ -835,7 +814,7 @@ export class Service {
data: DeepPartial<Project>, data: DeepPartial<Project>,
lrn?: string, lrn?: string,
auctionParams?: AuctionParams, auctionParams?: AuctionParams,
environmentVariables?: { environments: string[]; key: string; value: string }[], environmentVariables?: EnvironmentVariables[],
): Promise<Project | undefined> { ): Promise<Project | undefined> {
const organization = await this.db.getOrganization({ const organization = await this.db.getOrganization({
where: { where: {
@ -846,7 +825,7 @@ export class Service {
throw new Error('Organization does not exist'); throw new Error('Organization does not exist');
} }
const project = await this.db.addProject(user, organization.id, data);4 const project = await this.db.addProject(user, organization.id, data);
if (environmentVariables) { if (environmentVariables) {
await this.addEnvironmentVariables(project.id, environmentVariables); await this.addEnvironmentVariables(project.id, environmentVariables);

View File

@ -76,3 +76,9 @@ export interface AuctionParams {
maxPrice: string, maxPrice: string,
numProviders: number, numProviders: number,
} }
export interface EnvironmentVariables {
environments: string[],
key: string,
value: string,
}

View File

@ -125,7 +125,7 @@ const Configure = () => {
} }
}; };
const createEnvironmentVariablesHandler = useCallback( const handleFormSubmit = useCallback(
async (createFormData: FieldValues) => { async (createFormData: FieldValues) => {
const environmentVariables = createFormData.variables.map((variable: any) => { const environmentVariables = createFormData.variables.map((variable: any) => {
return { return {
@ -201,7 +201,7 @@ const Configure = () => {
<div className="flex flex-col gap-6 lg:gap-8 w-full"> <div className="flex flex-col gap-6 lg:gap-8 w-full">
<FormProvider {...methods}> <FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(createEnvironmentVariablesHandler)}> <form onSubmit={methods.handleSubmit(handleFormSubmit)}>
<div className="flex flex-col justify-start gap-4 mb-6"> <div className="flex flex-col justify-start gap-4 mb-6">
<Controller <Controller
name="option" name="option"

View File

@ -8,7 +8,6 @@ import { useGQLClient } from 'context/GQLClientContext';
import { EnvironmentVariablesFormValues } from '../../../../../types'; import { EnvironmentVariablesFormValues } from '../../../../../types';
import HorizontalLine from 'components/HorizontalLine'; import HorizontalLine from 'components/HorizontalLine';
import { Heading } from 'components/shared/Heading'; import { Heading } from 'components/shared/Heading';
// import { Checkbox } from 'components/shared/Checkbox';
import { PlusIcon } from 'components/shared/CustomIcon'; import { PlusIcon } from 'components/shared/CustomIcon';
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer'; import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
import { useToast } from 'components/shared/Toast'; import { useToast } from 'components/shared/Toast';
@ -79,7 +78,7 @@ export const EnvironmentVariablesTabPanel = () => {
await client.addEnvironmentVariables(id!, environmentVariables); await client.addEnvironmentVariables(id!, environmentVariables);
if (isEnvironmentVariablesAdded) { if (isEnvironmentVariablesAdded) {
// reset(); methods.reset();
setCreateNewVariable((cur) => !cur); setCreateNewVariable((cur) => !cur);
fetchEnvironmentVariables(id); fetchEnvironmentVariables(id);

View File

@ -1,6 +1,7 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form'; import { useFieldArray, useFormContext } from 'react-hook-form';
// TODO: Use custom checkbox component
import { Checkbox } from '@snowballtools/material-tailwind-react-fork'; import { Checkbox } from '@snowballtools/material-tailwind-react-fork';
import { Button } from 'components/shared/Button'; import { Button } from 'components/shared/Button';