Add fixtures for remaining entities in database initialization script (#36)
* Create fixture data for remaining entities and load it in db * Rename currProject to currentProject in frontend package * Handle review changes * Update readme for loading fixtures --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
890603061f
commit
2d7e56c0e1
@ -15,7 +15,7 @@
|
||||
- Build packages
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
yarn build --ignore frontend
|
||||
```
|
||||
|
||||
- Change directory to `packages/backend`
|
||||
@ -24,6 +24,12 @@
|
||||
cd packages/backend
|
||||
```
|
||||
|
||||
- Load fixtures in database
|
||||
|
||||
```bash
|
||||
yarn db:load:fixtures
|
||||
```
|
||||
|
||||
- Start the server
|
||||
|
||||
```bash
|
||||
|
@ -29,7 +29,7 @@
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"db:load:fixtures": "ts-node ./test/initialize-db.ts"
|
||||
"db:load:fixtures": "DEBUG=snowball:* ts-node ./test/initialize-db.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
|
92
packages/backend/test/fixtures/deployments.json
vendored
Normal file
92
packages/backend/test/fixtures/deployments.json
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"projectIndex": 0,
|
||||
"domainIndex":0,
|
||||
"title": "nextjs-boilerplate-1",
|
||||
"status": "Building",
|
||||
"environment": "Production",
|
||||
"isCurrent": false,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 0,
|
||||
"domainIndex":1,
|
||||
"title": "nextjs-boilerplate-2",
|
||||
"status": "Ready",
|
||||
"environment": "Preview",
|
||||
"isCurrent": true,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 0,
|
||||
"domainIndex":2,
|
||||
"title": "nextjs-boilerplate-3",
|
||||
"status": "Error",
|
||||
"environment": "Development",
|
||||
"isCurrent": false,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 1,
|
||||
"domainIndex":3,
|
||||
"title": "nextjs-boilerplate-1",
|
||||
"status": "Building",
|
||||
"environment": "Production",
|
||||
"isCurrent": false,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 1,
|
||||
"domainIndex":4,
|
||||
"title": "nextjs-boilerplate-2",
|
||||
"status": "Ready",
|
||||
"environment": "Preview",
|
||||
"isCurrent": true,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 1,
|
||||
"domainIndex":5,
|
||||
"title": "nextjs-boilerplate-3",
|
||||
"status": "Error",
|
||||
"environment": "Development",
|
||||
"isCurrent": false,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 2,
|
||||
"domainIndex":6,
|
||||
"title": "nextjs-boilerplate-1",
|
||||
"status": "Building",
|
||||
"environment": "Production",
|
||||
"isCurrent": false,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 2,
|
||||
"domainIndex":7,
|
||||
"title": "nextjs-boilerplate-2",
|
||||
"status": "Ready",
|
||||
"environment": "Preview",
|
||||
"isCurrent": true,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
},
|
||||
{
|
||||
"projectIndex": 2,
|
||||
"domainIndex":8,
|
||||
"title": "nextjs-boilerplate-3",
|
||||
"status": "Error",
|
||||
"environment": "Development",
|
||||
"isCurrent": false,
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz"
|
||||
}
|
||||
]
|
56
packages/backend/test/fixtures/domains.json
vendored
Normal file
56
packages/backend/test/fixtures/domains.json
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
[
|
||||
{
|
||||
"name": "randomurl.snowballtools.xyz",
|
||||
"status": "Live",
|
||||
"isRedirected": false,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "saugatt.com",
|
||||
"status": "Pending",
|
||||
"isRedirected": false,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "www.saugatt.com",
|
||||
"status": "Pending",
|
||||
"isRedirected": true,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "randomurl.snowballtools.xyz",
|
||||
"status": "Live",
|
||||
"isRedirected": false,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "saugatt.com",
|
||||
"status": "Pending",
|
||||
"isRedirected": false,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "www.saugatt.com",
|
||||
"status": "Pending",
|
||||
"isRedirected": true,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "randomurl.snowballtools.xyz",
|
||||
"status": "Live",
|
||||
"isRedirected": false,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "saugatt.com",
|
||||
"status": "Pending",
|
||||
"isRedirected": false,
|
||||
"branch": "test"
|
||||
},
|
||||
{
|
||||
"name": "www.saugatt.com",
|
||||
"status": "Pending",
|
||||
"isRedirected": true,
|
||||
"branch": "test"
|
||||
}
|
||||
]
|
62
packages/backend/test/fixtures/environment-variables.json
vendored
Normal file
62
packages/backend/test/fixtures/environment-variables.json
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
[
|
||||
{
|
||||
"projectIndex": 0,
|
||||
"key": "ABC",
|
||||
"value": "ABC",
|
||||
"environments": ["Production", "Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 0,
|
||||
"key": "XYZ",
|
||||
"value": "abc3",
|
||||
"environments": ["Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 1,
|
||||
"key": "ABC",
|
||||
"value": "ABC",
|
||||
"environments": ["Production", "Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 1,
|
||||
"key": "XYZ",
|
||||
"value": "abc3",
|
||||
"environments": ["Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 2,
|
||||
"key": "ABC",
|
||||
"value": "ABC",
|
||||
"environments": ["Production", "Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 2,
|
||||
"key": "XYZ",
|
||||
"value": "abc3",
|
||||
"environments": ["Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 3,
|
||||
"key": "ABC",
|
||||
"value": "ABC",
|
||||
"environments": ["Production", "Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 3,
|
||||
"key": "XYZ",
|
||||
"value": "abc3",
|
||||
"environments": ["Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 4,
|
||||
"key": "ABC",
|
||||
"value": "ABC",
|
||||
"environments": ["Production", "Preview"]
|
||||
},
|
||||
{
|
||||
"projectIndex": 4,
|
||||
"key": "XYZ",
|
||||
"value": "abc3",
|
||||
"environments": ["Preview"]
|
||||
}
|
||||
]
|
12
packages/backend/test/fixtures/project-members.json
vendored
Normal file
12
packages/backend/test/fixtures/project-members.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"memberIndex": 1,
|
||||
"projectIndex": 0,
|
||||
"permissions": ["View", "Edit"]
|
||||
},
|
||||
{
|
||||
"memberIndex": 2,
|
||||
"projectIndex": 0,
|
||||
"permissions": ["View", "Edit"]
|
||||
}
|
||||
]
|
@ -14,20 +14,37 @@ import { Deployment } from '../src/entity/Deployment';
|
||||
|
||||
const log = debug('snowball:initialize-database');
|
||||
|
||||
const DB_PATH = '../db/snowball';
|
||||
|
||||
const USER_DATA_PATH = './fixtures/users.json';
|
||||
const PROJECT_DATA_PATH = './fixtures/projects.json';
|
||||
const ORGANIZATION_DATA_PATH = './fixtures/organizations.json';
|
||||
const USER_ORGANIZATION_DATA_PATH = './fixtures/user-orgnizations.json';
|
||||
const PROJECT_MEMBER_DATA_PATH = './fixtures/project-members.json';
|
||||
const DOMAIN_DATA_PATH = './fixtures/domains.json';
|
||||
const DEPLOYMENT_DATA_PATH = './fixtures/deployments.json';
|
||||
const ENVIRONMENT_VARIABLE_DATA_PATH = './fixtures/environment-variables.json';
|
||||
|
||||
const loadAndSaveData = async <Entity extends ObjectLiteral>(entityType: EntityTarget<Entity>, dataSource: DataSource, filePath: string) => {
|
||||
const loadAndSaveData = async <Entity extends ObjectLiteral>(entityType: EntityTarget<Entity>, dataSource: DataSource, filePath: string, relations?: any | undefined) => {
|
||||
const entitiesData = await fs.readFile(filePath, 'utf-8');
|
||||
const entities = JSON.parse(entitiesData) as DeepPartial<Entity>[];
|
||||
const entities = JSON.parse(entitiesData);
|
||||
const entityRepository = dataSource.getRepository(entityType);
|
||||
|
||||
const savedEntity:Entity[] = [];
|
||||
|
||||
for (const entityData of entities) {
|
||||
const entity = entityRepository.create(entityData);
|
||||
let entity = entityRepository.create(entityData as DeepPartial<Entity>);
|
||||
|
||||
if (relations) {
|
||||
for (const field in relations) {
|
||||
const valueIndex = String(field + 'Index');
|
||||
|
||||
entity = {
|
||||
...entity,
|
||||
[field]: relations[field][entityData[valueIndex]]
|
||||
};
|
||||
}
|
||||
}
|
||||
const dbEntity = await entityRepository.save(entity);
|
||||
savedEntity.push(dbEntity);
|
||||
}
|
||||
@ -38,52 +55,69 @@ const loadAndSaveData = async <Entity extends ObjectLiteral>(entityType: EntityT
|
||||
const generateTestData = async (dataSource: DataSource) => {
|
||||
const savedUsers = await loadAndSaveData(User, dataSource, path.resolve(__dirname, USER_DATA_PATH));
|
||||
const savedOrgs = await loadAndSaveData(Organization, dataSource, path.resolve(__dirname, ORGANIZATION_DATA_PATH));
|
||||
const savedDomains = await loadAndSaveData(Domain, dataSource, path.resolve(__dirname, DOMAIN_DATA_PATH));
|
||||
|
||||
const projectsData = await fs.readFile(path.resolve(__dirname, PROJECT_DATA_PATH), 'utf-8');
|
||||
const projects = JSON.parse(projectsData);
|
||||
const projectRepository = dataSource.getRepository(Project);
|
||||
const projectRelations = {
|
||||
owner: savedUsers,
|
||||
organization: savedOrgs
|
||||
};
|
||||
|
||||
for (const projectData of projects) {
|
||||
const project = projectRepository.create(projectData as DeepPartial<Project>);
|
||||
project.owner = savedUsers[projectData.ownerIndex];
|
||||
project.organization = savedOrgs[projectData.organizationIndex];
|
||||
await projectRepository.save(project);
|
||||
}
|
||||
const savedProjects = await loadAndSaveData(Project, dataSource, path.resolve(__dirname, PROJECT_DATA_PATH), projectRelations);
|
||||
|
||||
const userOrgData = await fs.readFile(path.resolve(__dirname, USER_ORGANIZATION_DATA_PATH), 'utf-8');
|
||||
const userOrgs = JSON.parse(userOrgData);
|
||||
const userOrgRepository = dataSource.getRepository(UserOrganization);
|
||||
const userOrganizationRelations = {
|
||||
member: savedUsers,
|
||||
organization: savedOrgs
|
||||
};
|
||||
|
||||
for (const userOrgData of userOrgs) {
|
||||
const userOrg = userOrgRepository.create(userOrgData as DeepPartial<UserOrganization>);
|
||||
userOrg.member = savedUsers[userOrgData.memberIndex];
|
||||
userOrg.organization = savedOrgs[userOrgData.organizationIndex];
|
||||
await loadAndSaveData(UserOrganization, dataSource, path.resolve(__dirname, USER_ORGANIZATION_DATA_PATH), userOrganizationRelations);
|
||||
|
||||
await userOrgRepository.save(userOrg);
|
||||
const projectMemberRelations = {
|
||||
member: savedUsers,
|
||||
project: savedProjects
|
||||
};
|
||||
|
||||
await loadAndSaveData(ProjectMember, dataSource, path.resolve(__dirname, PROJECT_MEMBER_DATA_PATH), projectMemberRelations);
|
||||
|
||||
const deploymentRelations = {
|
||||
project: savedProjects,
|
||||
domain: savedDomains
|
||||
};
|
||||
|
||||
await loadAndSaveData(Deployment, dataSource, path.resolve(__dirname, DEPLOYMENT_DATA_PATH), deploymentRelations);
|
||||
|
||||
const environmentVariableRelations = {
|
||||
project: savedProjects
|
||||
};
|
||||
|
||||
await loadAndSaveData(EnvironmentVariable, dataSource, path.resolve(__dirname, ENVIRONMENT_VARIABLE_DATA_PATH), environmentVariableRelations);
|
||||
};
|
||||
|
||||
const checkFileExists = async (filePath: string) => {
|
||||
try {
|
||||
await fs.access(filePath, fs.constants.F_OK);
|
||||
return true;
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
const isDbPresent = await checkFileExists(path.resolve(__dirname, DB_PATH));
|
||||
|
||||
if (!isDbPresent) {
|
||||
const dataSource = new DataSource({
|
||||
type: 'better-sqlite3',
|
||||
database: 'db/snowball',
|
||||
synchronize: true,
|
||||
logging: true,
|
||||
entities: [
|
||||
User,
|
||||
Organization,
|
||||
Project,
|
||||
UserOrganization,
|
||||
EnvironmentVariable,
|
||||
Domain,
|
||||
ProjectMember,
|
||||
Deployment
|
||||
]
|
||||
entities: [path.join(__dirname, '../src/entity/*')]
|
||||
});
|
||||
|
||||
await dataSource.initialize();
|
||||
|
||||
await generateTestData(dataSource);
|
||||
}
|
||||
};
|
||||
|
||||
main().then(() => {
|
||||
|
@ -14,19 +14,19 @@ const Domains = () => {
|
||||
|
||||
const { projects } = useOutletContext<ProjectsOutletContext>();
|
||||
|
||||
const currProject = useMemo(() => {
|
||||
const currentProject = useMemo(() => {
|
||||
return projects.find((project) => {
|
||||
return project.id === id;
|
||||
});
|
||||
}, [id, projects]);
|
||||
|
||||
const linkedRepo = useMemo(() => {
|
||||
return currProject?.repositories.find(
|
||||
(repo: any) => repo.id === Number(currProject?.repositoryId),
|
||||
return currentProject?.repositories.find(
|
||||
(repo: any) => repo.id === Number(currentProject?.repositoryId),
|
||||
);
|
||||
}, [currProject]);
|
||||
}, [currentProject]);
|
||||
|
||||
const domains = currProject?.deployments
|
||||
const domains = currentProject?.deployments
|
||||
.filter((deployment) => {
|
||||
return deployment.domain != null;
|
||||
})
|
||||
@ -49,7 +49,7 @@ const Domains = () => {
|
||||
domain={domain}
|
||||
key={domain.id}
|
||||
repo={linkedRepo!}
|
||||
project={currProject!}
|
||||
project={currentProject!}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -38,7 +38,7 @@ export const EnvironmentVariablesTabPanel = () => {
|
||||
|
||||
const { projects } = useOutletContext<ProjectsOutletContext>();
|
||||
|
||||
const currProject = useMemo(() => {
|
||||
const currentProject = useMemo(() => {
|
||||
return projects.find((project) => {
|
||||
return project.id === id;
|
||||
});
|
||||
@ -77,9 +77,9 @@ export const EnvironmentVariablesTabPanel = () => {
|
||||
}, [isSubmitSuccessful, reset]);
|
||||
|
||||
const getEnvironmentVariable = useCallback((environment: Environments) => {
|
||||
return (currProject?.environmentVariables as EnvironmentVariable[]).filter(
|
||||
(item) => item.environments.includes(environment),
|
||||
);
|
||||
return (
|
||||
currentProject?.environmentVariables as EnvironmentVariable[]
|
||||
).filter((item) => item.environments.includes(environment));
|
||||
}, []);
|
||||
|
||||
const isFieldEmpty = useMemo(() => {
|
||||
|
@ -15,7 +15,6 @@ import DeleteProjectDialog from './DeleteProjectDialog';
|
||||
import ConfirmDialog from '../../../shared/ConfirmDialog';
|
||||
import { ProjectsOutletContext } from '../../../../types/project';
|
||||
|
||||
const PROJECT_ID = '62f87575-7a2b-4951-8156-9f9821j380d';
|
||||
const TEAMS = ['Airfoil'];
|
||||
const DEFAULT_SELECT_TEAM = undefined;
|
||||
|
||||
@ -37,7 +36,7 @@ const GeneralTabPanel = () => {
|
||||
const { id } = useParams();
|
||||
const { projects } = useOutletContext<ProjectsOutletContext>();
|
||||
|
||||
const currProject = useMemo(() => {
|
||||
const currentProject = useMemo(() => {
|
||||
return projects.find((project: any) => project.id === id);
|
||||
}, [id]);
|
||||
|
||||
@ -61,12 +60,14 @@ const GeneralTabPanel = () => {
|
||||
|
||||
const { handleSubmit, register } = useForm({
|
||||
defaultValues: {
|
||||
appName: currProject?.name,
|
||||
description: currProject?.description,
|
||||
appName: currentProject?.name,
|
||||
description: currentProject?.description,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{currentProject && (
|
||||
<>
|
||||
<form onSubmit={handleSubmit(() => {})}>
|
||||
<Typography variant="h6">Project info</Typography>
|
||||
@ -95,10 +96,10 @@ const GeneralTabPanel = () => {
|
||||
<Input
|
||||
crossOrigin={undefined}
|
||||
variant="outlined"
|
||||
value={PROJECT_ID}
|
||||
value={currentProject.id}
|
||||
size="md"
|
||||
disabled
|
||||
icon={<CopyIcon value={PROJECT_ID} />}
|
||||
icon={<CopyIcon value={currentProject.id} />}
|
||||
/>
|
||||
<Button type="submit" variant="gradient" size="sm" className="mt-1">
|
||||
Save
|
||||
@ -107,8 +108,8 @@ const GeneralTabPanel = () => {
|
||||
<div className="mb-1">
|
||||
<Typography variant="h6">Transfer project</Typography>
|
||||
<Typography variant="small">
|
||||
Transfer this app to your personal account or a team you are a member
|
||||
of.
|
||||
Transfer this app to your personal account or a team you are a
|
||||
member of.
|
||||
<Link to="" className="text-blue-500">
|
||||
Learn more
|
||||
</Link>
|
||||
@ -166,8 +167,8 @@ const GeneralTabPanel = () => {
|
||||
<div className="mb-1">
|
||||
<Typography variant="h6">Delete project</Typography>
|
||||
<Typography variant="small">
|
||||
The project will be permanently deleted, including its deployments and
|
||||
domains. This action is irreversible and can not be undone.
|
||||
The project will be permanently deleted, including its deployments
|
||||
and domains. This action is irreversible and can not be undone.
|
||||
</Typography>
|
||||
<Button
|
||||
variant="gradient"
|
||||
@ -184,6 +185,8 @@ const GeneralTabPanel = () => {
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -18,12 +18,12 @@ const MembersTabPanel = () => {
|
||||
// @ts-expect-error create context type for projects
|
||||
const { projects } = useOutletContext();
|
||||
|
||||
const currProject = useMemo(() => {
|
||||
const currentProject = useMemo(() => {
|
||||
return projects.find((project: any) => project.id === id);
|
||||
}, [id]);
|
||||
|
||||
const [updatedMembers, setUpdatedMembers] = useState([
|
||||
...currProject?.members,
|
||||
...currentProject?.members,
|
||||
]);
|
||||
|
||||
const addMemberHandler = useCallback((member: Member) => {
|
||||
@ -59,7 +59,7 @@ const MembersTabPanel = () => {
|
||||
member={member.member}
|
||||
key={member.id}
|
||||
isFirstCard={index === FIRST_MEMBER_CARD}
|
||||
isOwner={member.member.id === currProject?.owner.id}
|
||||
isOwner={member.member.id === currentProject?.owner.id}
|
||||
isPending={member.name === ''}
|
||||
permissions={member.permissions}
|
||||
handleDeletePendingMember={(id: number) => {
|
||||
|
Loading…
Reference in New Issue
Block a user