Use query builder to get projects without deployments
All checks were successful
Lint / lint (20.x) (pull_request) Successful in 4m58s
All checks were successful
Lint / lint (20.x) (pull_request) Successful in 4m58s
This commit is contained in:
parent
9461bd04f1
commit
aac2221af0
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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,
|
||||||
) => {
|
) => {
|
||||||
|
@ -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);
|
||||||
|
@ -76,3 +76,9 @@ export interface AuctionParams {
|
|||||||
maxPrice: string,
|
maxPrice: string,
|
||||||
numProviders: number,
|
numProviders: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EnvironmentVariables {
|
||||||
|
environments: string[],
|
||||||
|
key: string,
|
||||||
|
value: string,
|
||||||
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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);
|
||||||
|
@ -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';
|
||||||
|
Loading…
Reference in New Issue
Block a user