From 890603061f2f0c2654acf2b1d92681f3b29cc9fa Mon Sep 17 00:00:00 2001 From: Nabarun Gogoi Date: Wed, 24 Jan 2024 10:30:19 +0530 Subject: [PATCH] Add script to load fixture data in database (#34) * Add fixture data and populate database with it * Use node to run commands in package scripts * Move test directory out of src directory * Save projects with user and organization relation * Refactor and add generalized function to load data * Populate userOrganization entity with test data * Change project id type from number to string --------- Co-authored-by: neeraj --- packages/backend/package.json | 11 ++- .../backend/test/fixtures/organizations.json | 8 ++ packages/backend/test/fixtures/projects.json | 57 +++++++++++ .../test/fixtures/user-orgnizations.json | 22 +++++ packages/backend/test/fixtures/users.json | 14 +++ packages/backend/test/initialize-db.ts | 94 +++++++++++++++++++ .../projects/project/settings/Domains.tsx | 10 +- .../settings/EnvironmentVariablesTabPanel.tsx | 6 +- .../frontend/src/pages/projects/Project.tsx | 15 +-- packages/frontend/src/types/project.ts | 3 +- yarn.lock | 51 +++++++++- 11 files changed, 265 insertions(+), 26 deletions(-) create mode 100644 packages/backend/test/fixtures/organizations.json create mode 100644 packages/backend/test/fixtures/projects.json create mode 100644 packages/backend/test/fixtures/user-orgnizations.json create mode 100644 packages/backend/test/fixtures/users.json create mode 100644 packages/backend/test/initialize-db.ts diff --git a/packages/backend/package.json b/packages/backend/package.json index a014115..9e3dcbc 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -21,16 +21,21 @@ "typescript": "^5.3.3" }, "scripts": { - "start": "DEBUG=snowball:* ts-node ./src/index.ts", - "build": "tsc", + "start": "DEBUG=snowball:* node --enable-source-maps ./dist/index.js", + "start:dev": "DEBUG=snowball:* ts-node ./src/index.ts", + "copy-assets": "copyfiles -u 1 src/**/*.gql dist/", + "clean": "rm -rf ./dist", + "build": "yarn clean && tsc && yarn copy-assets", "lint": "eslint .", "format": "prettier --write .", - "format:check": "prettier --check ." + "format:check": "prettier --check .", + "db:load:fixtures": "ts-node ./test/initialize-db.ts" }, "devDependencies": { "@types/fs-extra": "^11.0.4", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", + "copyfiles": "^2.4.1", "better-sqlite3": "^9.2.2", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", diff --git a/packages/backend/test/fixtures/organizations.json b/packages/backend/test/fixtures/organizations.json new file mode 100644 index 0000000..32e78b6 --- /dev/null +++ b/packages/backend/test/fixtures/organizations.json @@ -0,0 +1,8 @@ +[ + { + "name": "Snowball Tools" + }, + { + "name": "AirFoil" + } +] diff --git a/packages/backend/test/fixtures/projects.json b/packages/backend/test/fixtures/projects.json new file mode 100644 index 0000000..b6ae8dc --- /dev/null +++ b/packages/backend/test/fixtures/projects.json @@ -0,0 +1,57 @@ +[ + { + "ownerIndex":0, + "organizationIndex":0, + "name": "testProject", + "repository": "test", + "prodBranch": "main", + "description": "test", + "template": "test", + "framework": "test", + "webhooks": [] + }, + { + "ownerIndex":1, + "organizationIndex":0, + "name": "testProject-2", + "repository": "test-2", + "prodBranch": "main", + "description": "test-2", + "template": "test-2", + "framework": "test-2", + "webhooks": [] + }, + { + "ownerIndex":2, + "organizationIndex":0, + "name": "iglootools", + "repository": "test-3", + "prodBranch": "main", + "description": "test-3", + "template": "test-3", + "framework": "test-3", + "webhooks": [] + }, + { + "ownerIndex":1, + "organizationIndex":0, + "name": "iglootools-2", + "repository": "test-4", + "prodBranch": "main", + "description": "test-4", + "template": "test-4", + "framework": "test-4", + "webhooks": [] + }, + { + "ownerIndex":0, + "organizationIndex":1, + "name": "snowball-2", + "repository": "test-5", + "prodBranch": "main", + "description": "test-5", + "template": "test-5", + "framework": "test-5", + "webhooks": [] + } +] diff --git a/packages/backend/test/fixtures/user-orgnizations.json b/packages/backend/test/fixtures/user-orgnizations.json new file mode 100644 index 0000000..adff4ae --- /dev/null +++ b/packages/backend/test/fixtures/user-orgnizations.json @@ -0,0 +1,22 @@ +[ + { + "role": "Owner", + "memberIndex": 0, + "organizationIndex": 0 + }, + { + "role": "Maintainer", + "memberIndex": 1, + "organizationIndex": 0 + }, + { + "role": "Owner", + "memberIndex": 2, + "organizationIndex": 0 + }, + { + "role": "Owner", + "memberIndex": 0, + "organizationIndex": 1 + } +] diff --git a/packages/backend/test/fixtures/users.json b/packages/backend/test/fixtures/users.json new file mode 100644 index 0000000..d2e4fb4 --- /dev/null +++ b/packages/backend/test/fixtures/users.json @@ -0,0 +1,14 @@ +[ + { + "name": "Saugat Yadav", + "email": "saugaty@airfoil.studio" + }, + { + "name": "Gideon Low", + "email": "gideonl@airfoil.studio" + }, + { + "name": "Sushan Yadav", + "email": "sushany@airfoil.studio" + } +] diff --git a/packages/backend/test/initialize-db.ts b/packages/backend/test/initialize-db.ts new file mode 100644 index 0000000..56a20ff --- /dev/null +++ b/packages/backend/test/initialize-db.ts @@ -0,0 +1,94 @@ +import { DataSource, DeepPartial, EntityTarget, ObjectLiteral } from 'typeorm'; +import * as fs from 'fs/promises'; +import debug from 'debug'; +import path from 'path'; + +import { User } from '../src/entity/User'; +import { Organization } from '../src/entity/Organization'; +import { Project } from '../src/entity/Project'; +import { UserOrganization } from '../src/entity/UserOrganization'; +import { EnvironmentVariable } from '../src/entity/EnvironmentVariable'; +import { Domain } from '../src/entity/Domain'; +import { ProjectMember } from '../src/entity/ProjectMember'; +import { Deployment } from '../src/entity/Deployment'; + +const log = debug('snowball:initialize-database'); + +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 loadAndSaveData = async (entityType: EntityTarget, dataSource: DataSource, filePath: string) => { + const entitiesData = await fs.readFile(filePath, 'utf-8'); + const entities = JSON.parse(entitiesData) as DeepPartial[]; + const entityRepository = dataSource.getRepository(entityType); + + const savedEntity:Entity[] = []; + + for (const entityData of entities) { + const entity = entityRepository.create(entityData); + const dbEntity = await entityRepository.save(entity); + savedEntity.push(dbEntity); + } + + return savedEntity; +}; + +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 projectsData = await fs.readFile(path.resolve(__dirname, PROJECT_DATA_PATH), 'utf-8'); + const projects = JSON.parse(projectsData); + const projectRepository = dataSource.getRepository(Project); + + for (const projectData of projects) { + const project = projectRepository.create(projectData as DeepPartial); + project.owner = savedUsers[projectData.ownerIndex]; + project.organization = savedOrgs[projectData.organizationIndex]; + await projectRepository.save(project); + } + + const userOrgData = await fs.readFile(path.resolve(__dirname, USER_ORGANIZATION_DATA_PATH), 'utf-8'); + const userOrgs = JSON.parse(userOrgData); + const userOrgRepository = dataSource.getRepository(UserOrganization); + + for (const userOrgData of userOrgs) { + const userOrg = userOrgRepository.create(userOrgData as DeepPartial); + userOrg.member = savedUsers[userOrgData.memberIndex]; + userOrg.organization = savedOrgs[userOrgData.organizationIndex]; + + await userOrgRepository.save(userOrg); + } +}; + +const main = async () => { + const dataSource = new DataSource({ + type: 'better-sqlite3', + database: 'db/snowball', + synchronize: true, + logging: true, + entities: [ + User, + Organization, + Project, + UserOrganization, + EnvironmentVariable, + Domain, + ProjectMember, + Deployment + ] + }); + + await dataSource.initialize(); + + await generateTestData(dataSource); +}; + +main().then(() => { + log('Data loaded successfully'); +}) + .catch((err) => { + log(err); + }); diff --git a/packages/frontend/src/components/projects/project/settings/Domains.tsx b/packages/frontend/src/components/projects/project/settings/Domains.tsx index 5a86c75..1874a1e 100644 --- a/packages/frontend/src/components/projects/project/settings/Domains.tsx +++ b/packages/frontend/src/components/projects/project/settings/Domains.tsx @@ -15,10 +15,10 @@ const Domains = () => { const { projects } = useOutletContext(); const currProject = useMemo(() => { - return projects.find((data) => { - return Number(data?.id) === Number(id); + return projects.find((project) => { + return project.id === id; }); - }, [id]); + }, [id, projects]); const linkedRepo = useMemo(() => { return currProject?.repositories.find( @@ -27,10 +27,10 @@ const Domains = () => { }, [currProject]); const domains = currProject?.deployments - .filter((deployment: any) => { + .filter((deployment) => { return deployment.domain != null; }) - .map((deployment: any) => deployment.domain); + .map((deployment) => deployment.domain); return ( <> diff --git a/packages/frontend/src/components/projects/project/settings/EnvironmentVariablesTabPanel.tsx b/packages/frontend/src/components/projects/project/settings/EnvironmentVariablesTabPanel.tsx index 67c2ebf..548b90e 100644 --- a/packages/frontend/src/components/projects/project/settings/EnvironmentVariablesTabPanel.tsx +++ b/packages/frontend/src/components/projects/project/settings/EnvironmentVariablesTabPanel.tsx @@ -39,8 +39,10 @@ export const EnvironmentVariablesTabPanel = () => { const { projects } = useOutletContext(); const currProject = useMemo(() => { - return projects.find((data) => Number(data.id) === Number(id)); - }, [id]); + return projects.find((project) => { + return project.id === id; + }); + }, [id, projects]); const { handleSubmit, diff --git a/packages/frontend/src/pages/projects/Project.tsx b/packages/frontend/src/pages/projects/Project.tsx index 2e4782f..e8cf9b4 100644 --- a/packages/frontend/src/pages/projects/Project.tsx +++ b/packages/frontend/src/pages/projects/Project.tsx @@ -7,22 +7,17 @@ import HorizontalLine from '../../components/HorizontalLine'; import ProjectTabs from '../../components/projects/project/ProjectTabs'; import { ProjectsOutletContext } from '../../types/project'; -const getProject = (projects: any, id: number) => { - return projects.find((project: any) => { - return Number(project.id) === id; - }); -}; - const Project = () => { const { id } = useParams(); const navigate = useNavigate(); const { projects } = useOutletContext(); - const project = useMemo( - () => getProject(projects, Number(id)), - [id, projects], - ); + const project = useMemo(() => { + return projects.find((project) => { + return project.id === id; + }); + }, [id, projects]); return (
diff --git a/packages/frontend/src/types/project.ts b/packages/frontend/src/types/project.ts index 950b136..f08fc07 100644 --- a/packages/frontend/src/types/project.ts +++ b/packages/frontend/src/types/project.ts @@ -6,7 +6,7 @@ export interface ProjectDetails { description: string; url: string; domain: string | null; - id: number; + id: string; createdAt: string; createdBy: string; deployments: DeploymentDetails[]; @@ -31,6 +31,7 @@ export interface MemberPermission { export interface DeploymentDetails { title: string; isProduction: boolean; + domain: DomainDetails; status: Status; branch: string; environment: Environments; diff --git a/yarn.lock b/yarn.lock index c033b68..d5ad4af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5372,6 +5372,19 @@ cookie@0.5.0: resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + core-js-compat@^3.31.0, core-js-compat@^3.33.1: version "3.34.0" resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz" @@ -7540,7 +7553,7 @@ glob@^10.2.2, glob@^10.3.10: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -8090,7 +8103,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -8504,6 +8517,11 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + isarray@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" @@ -9857,7 +9875,7 @@ minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.3, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -10168,6 +10186,14 @@ node-releases@^2.0.14: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +noms@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" + integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + nopt@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" @@ -12060,6 +12086,16 @@ readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^3.6.0, readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -12989,6 +13025,11 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" @@ -13388,7 +13429,7 @@ throat@^6.0.1: resolved "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz" integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== -through2@^2.0.0: +through2@^2.0.0, through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -14656,7 +14697,7 @@ yargs@17.7.2, yargs@^17.6.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@^16.0.0, yargs@^16.2.0: +yargs@^16.0.0, yargs@^16.1.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==