diff --git a/README.md b/README.md index 3accec13..c46cbbb3 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ - Load fixtures in database ```bash - yarn db:load:fixtures + yarn test:db:load:fixtures ``` - Set `gitHub.oAuth.clientId` and `gitHub.oAuth.clientSecret` in backend [config file](packages/backend/environments/local.toml) @@ -66,7 +66,7 @@ - Run the script to create bond, reserve the authority and set authority bond ```bash - yarn registry:init + yarn test:registry:init # snowball:initialize-registry bondId: 6af0ab81973b93d3511ae79841756fb5da3fd2f70ea1279e81fae7c9b19af6c4 +0ms ``` diff --git a/packages/backend/environments/local.toml b/packages/backend/environments/local.toml index 7ca5521f..b5b5d03a 100644 --- a/packages/backend/environments/local.toml +++ b/packages/backend/environments/local.toml @@ -13,6 +13,7 @@ clientSecret = "" [registryConfig] + fetchDeploymentRecordDelay = 5000 restEndpoint = "http://localhost:1317" gqlEndpoint = "http://localhost:9473/api" chainId = "laconic_9000-1" diff --git a/packages/backend/package.json b/packages/backend/package.json index c28f72c7..83138f1d 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -36,10 +36,10 @@ "lint": "eslint .", "format": "prettier --write .", "format:check": "prettier --check .", - "registry:init": "DEBUG=snowball:* ts-node ./test/initialize-registry.ts", - "registry:publish-deploy-records": "DEBUG=snowball:* ts-node ./test/publish-deploy-records.ts", - "db:load:fixtures": "DEBUG=snowball:* ts-node ./test/initialize-db.ts", - "db:delete": "DEBUG=snowball:* ts-node ./test/delete-db.ts" + "test:registry:init": "DEBUG=snowball:* ts-node ./test/initialize-registry.ts", + "test:registry:publish-deploy-records": "DEBUG=snowball:* ts-node ./test/publish-deploy-records.ts", + "test:db:load:fixtures": "DEBUG=snowball:* ts-node ./test/initialize-db.ts", + "test:db:delete": "DEBUG=snowball:* ts-node ./test/delete-db.ts" }, "devDependencies": { "@types/fs-extra": "^11.0.4", diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index 50b34145..1a98a657 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -22,6 +22,7 @@ export interface RegistryConfig { chainId: string; privateKey: string; bondId: string; + fetchDeploymentRecordDelay: number; fee: { amount: string; denom: string; diff --git a/packages/backend/src/database.ts b/packages/backend/src/database.ts index a2959773..7c76f928 100644 --- a/packages/backend/src/database.ts +++ b/packages/backend/src/database.ts @@ -126,8 +126,18 @@ export class Database { return projects; } + /** + * Get deployments with specified filter + */ + async getDeployments (options: FindManyOptions): Promise { + const deploymentRepository = this.dataSource.getRepository(Deployment); + const deployments = await deploymentRepository.find(options); + + return deployments; + } + async getDeploymentsByProjectId (projectId: string): Promise { - const deployments = await this.getDeployments({ + return this.getDeployments({ relations: { project: true, domain: true, @@ -142,15 +152,6 @@ export class Database { createdAt: 'DESC' } }); - - return deployments; - } - - async getDeployments (options: FindManyOptions): Promise { - const deploymentRepository = this.dataSource.getRepository(Deployment); - const deployments = await deploymentRepository.find(options); - - return deployments; } async getDeployment (options: FindOneOptions): Promise { @@ -167,7 +168,7 @@ export class Database { return domains; } - async addDeployement (data: DeepPartial): Promise { + async addDeployment (data: DeepPartial): Promise { const deploymentRepository = this.dataSource.getRepository(Deployment); const id = nanoid(); diff --git a/packages/backend/src/entity/Deployment.ts b/packages/backend/src/entity/Deployment.ts index 76238f32..62d3f38f 100644 --- a/packages/backend/src/entity/Deployment.ts +++ b/packages/backend/src/entity/Deployment.ts @@ -12,6 +12,7 @@ import { import { Project } from './Project'; import { Domain } from './Domain'; import { User } from './User'; +import { AppDeploymentRecordAttributes } from '../types'; export enum Environment { Production = 'Production', @@ -45,6 +46,9 @@ export class Deployment { @PrimaryColumn('varchar') id!: string; + @Column() + projectId!: string; + @ManyToOne(() => Project, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'projectId' }) project!: Project; @@ -69,10 +73,16 @@ export class Deployment { url!: string | null; @Column('varchar') - registryRecordId!: string; + applicationRecordId!: string; @Column('simple-json') - registryRecordData!: ApplicationRecord; + applicationRecordData!: ApplicationRecord; + + @Column('varchar', { nullable: true }) + applicationDeploymentRecordId!: string | null; + + @Column('simple-json', { nullable: true }) + applicationDeploymentRecordData!: AppDeploymentRecordAttributes | null; @Column({ enum: Environment diff --git a/packages/backend/src/entity/Project.ts b/packages/backend/src/entity/Project.ts index 667d120c..86fa7b3d 100644 --- a/packages/backend/src/entity/Project.ts +++ b/packages/backend/src/entity/Project.ts @@ -53,10 +53,10 @@ export class Project { prodBranch!: string; @Column('varchar', { nullable: true }) - registryRecordId!: string | null; + applicationDeploymentRequestId!: string | null; @Column('simple-json', { nullable: true }) - registryRecordData!: ApplicationDeploymentRequest | null; + applicationDeploymentRequestData!: ApplicationDeploymentRequest | null; @Column('text', { default: '' }) description!: string; diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index d29f3c32..7a871a28 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -31,7 +31,7 @@ export const main = async (): Promise => { await db.init(); const registry = new Registry(registryConfig); - const service = new Service({ gitHubConfig: gitHub }, db, app, registry); + const service = new Service({ gitHubConfig: gitHub, registryConfig }, db, app, registry); const typeDefs = fs.readFileSync(path.join(__dirname, 'schema.gql')).toString(); const resolvers = await createResolvers(service); diff --git a/packages/backend/src/registry.ts b/packages/backend/src/registry.ts index 02dc924b..108318bb 100644 --- a/packages/backend/src/registry.ts +++ b/packages/backend/src/registry.ts @@ -7,13 +7,14 @@ import { Registry as LaconicRegistry } from '@cerc-io/laconic-sdk'; import { RegistryConfig } from './config'; import { ApplicationDeploymentRequest } from './entity/Project'; -import { ApplicationRecord } from './entity/Deployment'; -import { PackageJSON } from './types'; +import { ApplicationRecord, Deployment } from './entity/Deployment'; +import { AppDeploymentRecord, PackageJSON } from './types'; const log = debug('snowball:registry'); const APP_RECORD_TYPE = 'ApplicationRecord'; -const DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRequest'; +const APP_DEPLOYMENT_REQUEST_TYPE = 'ApplicationDeploymentRequest'; +const APP_DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRecord'; // TODO: Move registry code to laconic-sdk/watcher-ts export class Registry { @@ -35,7 +36,7 @@ export class Registry { commitHash: string, appType: string, repoUrl: string - }): Promise<{registryRecordId: string, registryRecordData: ApplicationRecord}> { + }): Promise<{applicationRecordId: string, applicationRecordData: ApplicationRecord}> { assert(packageJSON.name, "name field doesn't exist in package.json"); // Use laconic-sdk to publish record // Reference: https://git.vdb.to/cerc-io/test-progressive-web-app/src/branch/main/scripts/publish-app-record.sh @@ -87,7 +88,7 @@ export class Registry { await this.registry.setName({ cid: result.data.id, crn: `${crn}@${applicationRecord.app_version}` }, this.registryConfig.privateKey, this.registryConfig.fee); await this.registry.setName({ cid: result.data.id, crn: `${crn}@${applicationRecord.repository_ref}` }, this.registryConfig.privateKey, this.registryConfig.fee); - return { registryRecordId: result.data.id, registryRecordData: applicationRecord }; + return { applicationRecordId: result.data.id, applicationRecordData: applicationRecord }; } async createApplicationDeploymentRequest (data: { @@ -96,8 +97,8 @@ export class Registry { repository: string, environmentVariables: { [key: string]: string } }): Promise<{ - registryRecordId: string, - registryRecordData: ApplicationDeploymentRequest + applicationDeploymentRequestId: string, + applicationDeploymentRequestData: ApplicationDeploymentRequest }> { const crn = this.getCrn(data.appName); const records = await this.registry.resolveNames([crn]); @@ -109,7 +110,7 @@ export class Registry { // Create record of type ApplicationDeploymentRequest and publish const applicationDeploymentRequest = { - type: DEPLOYMENT_RECORD_TYPE, + type: APP_DEPLOYMENT_REQUEST_TYPE, version: '1.0.0', name: `${applicationRecord.attributes.name}@${applicationRecord.attributes.app_version}`, application: `${crn}@${applicationRecord.attributes.app_version}`, @@ -141,7 +142,21 @@ export class Registry { log(`Application deployment request record published: ${result.data.id}`); log('Application deployment request data:', applicationDeploymentRequest); - return { registryRecordId: result.data.id, registryRecordData: applicationDeploymentRequest }; + return { applicationDeploymentRequestId: result.data.id, applicationDeploymentRequestData: applicationDeploymentRequest }; + } + + /** + * Fetch ApplicationDeploymentRecords for deployments + */ + async getDeploymentRecords (deployments: Deployment[]): Promise { + // Fetch ApplicationDeploymentRecords for corresponding ApplicationRecord set in deployments + // TODO: Implement Laconicd GQL query to filter records by multiple values for an attribute + const records = await this.registry.queryRecords({ + type: APP_DEPLOYMENT_RECORD_TYPE + }, true); + + // Filter records with ApplicationRecord ids + return records.filter((record: AppDeploymentRecord) => deployments.some(deployment => deployment.applicationRecordId === record.attributes.application)); } getCrn (packageJsonName: string): string { diff --git a/packages/backend/src/resolvers.ts b/packages/backend/src/resolvers.ts index 02602aae..f583bdab 100644 --- a/packages/backend/src/resolvers.ts +++ b/packages/backend/src/resolvers.ts @@ -30,7 +30,7 @@ export const createResolvers = async (service: Service): Promise => { }, deployments: async (_: any, { projectId }: { projectId: string }) => { - return service.getDeployementsByProjectId(projectId); + return service.getDeploymentsByProjectId(projectId); }, environmentVariables: async (_: any, { projectId }: { projectId: string }) => { diff --git a/packages/backend/src/schema.gql b/packages/backend/src/schema.gql index 8d048078..620dec72 100644 --- a/packages/backend/src/schema.gql +++ b/packages/backend/src/schema.gql @@ -91,7 +91,7 @@ type Deployment { branch: String! commitHash: String! commitMessage: String! - url: String! + url: String environment: Environment! isCurrent: Boolean! status: DeploymentStatus! diff --git a/packages/backend/src/service.ts b/packages/backend/src/service.ts index 8edb63a0..b2ba8fc1 100644 --- a/packages/backend/src/service.ts +++ b/packages/backend/src/service.ts @@ -14,14 +14,16 @@ import { Project } from './entity/Project'; import { Permission, ProjectMember } from './entity/ProjectMember'; import { User } from './entity/User'; import { Registry } from './registry'; -import { GitHubConfig } from './config'; -import { GitPushEventPayload } from './types'; +import { GitHubConfig, RegistryConfig } from './config'; +import { AppDeploymentRecord, GitPushEventPayload } from './types'; const log = debug('snowball:service'); + const GITHUB_UNIQUE_WEBHOOK_ERROR = 'Hook already exists on this repository'; interface Config { gitHubConfig: GitHubConfig + registryConfig: RegistryConfig } export class Service { @@ -30,11 +32,113 @@ export class Service { private registry: Registry; private config: Config; + private deployRecordCheckTimeout?: NodeJS.Timeout; + constructor (config: Config, db: Database, app: OAuthApp, registry: Registry) { this.db = db; this.oauthApp = app; this.registry = registry; this.config = config; + this.init(); + } + + /** + * Initialize services + */ + init (): void { + // Start check for ApplicationDeploymentRecords asynchronously + this.checkDeployRecordsAndUpdate(); + } + + /** + * Destroy services + */ + destroy (): void { + clearTimeout(this.deployRecordCheckTimeout); + } + + /** + * Checks for ApplicationDeploymentRecord and update corresponding deployments + * Continues check in loop after a delay of DEPLOY_RECORD_CHECK_DELAY_MS + */ + async checkDeployRecordsAndUpdate (): Promise { + // Fetch deployments in building state + const deployments = await this.db.getDeployments({ + where: { + status: DeploymentStatus.Building + // TODO: Fetch and check records for recent deployments + } + }); + + if (deployments.length) { + log(`Found ${deployments.length} deployments in ${DeploymentStatus.Building} state`); + + // Fetch ApplicationDeploymentRecord for deployments + const records = await this.registry.getDeploymentRecords(deployments); + log(`Found ${records.length} ApplicationDeploymentRecords`); + + // Update deployments for which ApplicationDeploymentRecords were returned + await this.updateDeploymentsWithRecordData(records); + } + + this.deployRecordCheckTimeout = setTimeout(() => { + this.checkDeployRecordsAndUpdate(); + }, this.config.registryConfig.fetchDeploymentRecordDelay); + } + + /** + * Update deployments with ApplicationDeploymentRecord data + */ + async updateDeploymentsWithRecordData (records: AppDeploymentRecord[]): Promise { + // Get deployments for ApplicationDeploymentRecords + const deployments = await this.db.getDeployments({ + where: records.map(record => ({ + applicationRecordId: record.attributes.application + })), + order: { + createdAt: 'DESC' + } + }); + + // Get project IDs of deployments that are in production environment + const productionDeploymentProjectIds = deployments.reduce((acc, deployment): Set => { + if (deployment.environment === Environment.Production) { + acc.add(deployment.projectId); + } + + return acc; + }, new Set()); + + // Set old deployments isCurrent to false + await Promise.all(Array.from(productionDeploymentProjectIds).map( + // TODO: Add DB method to update multiple deployments in single query + async (projectId) => this.db.updateDeployment({ projectId }, { isCurrent: false }) + )); + + const recordToDeploymentsMap = deployments.reduce((acc: {[key: string]: Deployment}, deployment) => { + acc[deployment.applicationRecordId] = deployment; + return acc; + }, {}); + + // Update deployment data for ApplicationDeploymentRecords + const deploymentUpdatePromises = records.map(async (record) => { + const deployment = recordToDeploymentsMap[record.attributes.application]; + + await this.db.updateDeploymentById( + deployment.id, + { + applicationDeploymentRecordId: record.id, + applicationDeploymentRecordData: record.attributes, + url: record.attributes.url, + status: DeploymentStatus.Ready, + isCurrent: deployment.environment === Environment.Production + } + ); + + log(`Updated deployment deployment ${deployment.id} with URL ${record.attributes.url}`); + }); + + await Promise.all(deploymentUpdatePromises); } async getUser (userId: string): Promise { @@ -67,7 +171,7 @@ export class Service { return dbProjects; } - async getDeployementsByProjectId (projectId: string): Promise { + async getDeploymentsByProjectId (projectId: string): Promise { const dbDeployments = await this.db.getDeploymentsByProjectId(projectId); return dbDeployments; } @@ -187,7 +291,7 @@ export class Service { const octokit = await this.getOctokit(userId); - const newDeployement = await this.createDeployment(userId, + const newDeployment = await this.createDeployment(userId, octokit, { project: oldDeployment.project, @@ -199,7 +303,7 @@ export class Service { commitMessage: oldDeployment.commitMessage }); - return newDeployement; + return newDeployment; } async createDeployment ( @@ -232,24 +336,13 @@ export class Service { } // TODO: Set environment variables for each deployment (environment variables can`t be set in application record) - const { registryRecordId, registryRecordData } = await this.registry.createApplicationRecord({ + const { applicationRecordId, applicationRecordData } = await this.registry.createApplicationRecord({ packageJSON, appType: data.project!.template!, commitHash: data.commitHash!, repoUrl: recordData.repoUrl }); - // Check if new deployment is set to current - if (data.isCurrent) { - // Update previous current deployment - await this.db.updateDeployment({ - project: { - id: data.project.id - }, - isCurrent: true - }, { isCurrent: false }); - } - // Update previous deployment with prod branch domain // TODO: Fix unique constraint error for domain await this.db.updateDeployment({ @@ -258,7 +351,7 @@ export class Service { domain: null }); - const newDeployement = await this.db.addDeployement({ + const newDeployment = await this.db.addDeployment({ project: data.project, branch: data.branch, commitHash: data.commitHash, @@ -266,16 +359,16 @@ export class Service { environment: data.environment, isCurrent: data.isCurrent, status: DeploymentStatus.Building, - registryRecordId, - registryRecordData, + applicationRecordId, + applicationRecordData, domain: data.domain, createdBy: Object.assign(new User(), { id: userId }) }); - log(`Created deployment ${newDeployement.id} and published application record ${registryRecordId}`); - return newDeployement; + log(`Created deployment ${newDeployment.id} and published application record ${applicationRecordId}`); + return newDeployment; } async addProject (userId: string, organizationSlug: string, data: DeepPartial): Promise { @@ -327,17 +420,17 @@ export class Service { return acc; }, {} as { [key: string]: string }); - const { registryRecordId, registryRecordData } = await this.registry.createApplicationDeploymentRequest( + const { applicationDeploymentRequestId, applicationDeploymentRequestData } = await this.registry.createApplicationDeploymentRequest( { - appName: newDeployment.registryRecordData.name!, + appName: newDeployment.applicationRecordData.name!, commitHash: latestCommit.sha, repository: repoDetails.html_url, environmentVariables: environmentVariablesObj }); await this.db.updateProjectById(project.id, { - registryRecordId, - registryRecordData + applicationDeploymentRequestId, + applicationDeploymentRequestData }); await this.createRepoHook(octokit, project); @@ -444,7 +537,7 @@ export class Service { const octokit = await this.getOctokit(userId); - const newDeployement = await this.createDeployment(userId, + const newDeployment = await this.createDeployment(userId, octokit, { project: oldDeployment.project, @@ -457,7 +550,7 @@ export class Service { commitMessage: oldDeployment.commitMessage }); - return newDeployement; + return newDeployment; } async rollbackDeployment (projectId: string, deploymentId: string): Promise { @@ -475,7 +568,7 @@ export class Service { }); if (!oldCurrentDeployment) { - throw new Error('Current deployement doesnot exist'); + throw new Error('Current deployment doesnot exist'); } const oldCurrentDeploymentUpdate = await this.db.updateDeploymentById(oldCurrentDeployment.id, { isCurrent: false, domain: null }); diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 9fb154cb..71626645 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -25,3 +25,27 @@ export interface GitPushEventPayload { message: string; }; } + +export interface AppDeploymentRecordAttributes { + application: string; + dns: string; + meta: string; + name: string; + request: string; + type: string; + url: string; + version: string; +} + +interface RegistryRecord { + id: string; + names: string[] | null; + owners: string[]; + bondId: string; + createTime: string; + expiryTime: string; +} + +export interface AppDeploymentRecord extends RegistryRecord { + attributes: AppDeploymentRecordAttributes +} diff --git a/packages/backend/test/fixtures/deployments.json b/packages/backend/test/fixtures/deployments.json index 25176713..5eb682a8 100644 --- a/packages/backend/test/fixtures/deployments.json +++ b/packages/backend/test/fixtures/deployments.json @@ -7,8 +7,8 @@ "status": "Ready", "environment": "Production", "isCurrent": true, - "registryRecordId": "qbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "qbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "main", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -22,8 +22,8 @@ "status": "Ready", "environment": "Preview", "isCurrent": false, - "registryRecordId": "wbafyreihvzya6ovp4yfpkqnddkui2iw7thbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "wbafyreihvzya6ovp4yfpkqnddkui2iw7thbhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -37,8 +37,8 @@ "status": "Ready", "environment": "Development", "isCurrent": false, - "registryRecordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -52,8 +52,8 @@ "status": "Ready", "environment": "Production", "isCurrent": false, - "registryRecordId": "rbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhw74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "rbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhw74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "prod", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -67,8 +67,8 @@ "status": "Ready", "environment": "Production", "isCurrent": true, - "registryRecordId": "tbafyreihvzya6ovp4yfpqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "tbafyreihvzya6ovp4yfpqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "main", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -82,8 +82,8 @@ "status": "Ready", "environment": "Preview", "isCurrent": false, - "registryRecordId": "ybafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "ybafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -97,8 +97,8 @@ "status": "Ready", "environment": "Development", "isCurrent": false, - "registryRecordId": "ubafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "ubafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvfhrowoi", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -112,8 +112,8 @@ "status": "Ready", "environment": "Production", "isCurrent": true, - "registryRecordId": "ibayreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "ibayreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "main", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -127,8 +127,8 @@ "status": "Ready", "environment": "Preview", "isCurrent": false, - "registryRecordId": "obafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationRecordId": "obafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -142,8 +142,8 @@ "status": "Ready", "environment": "Development", "isCurrent": false, - "registryRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", - "registryRecordData": {}, + "applicationRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", @@ -157,8 +157,8 @@ "status": "Ready", "environment": "Production", "isCurrent": true, - "registryRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", - "registryRecordData": {}, + "applicationRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", + "applicationRecordData": {}, "branch": "test", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitMessage": "subscription added", diff --git a/packages/backend/test/fixtures/projects.json b/packages/backend/test/fixtures/projects.json index f2def3f2..55c5ee23 100644 --- a/packages/backend/test/fixtures/projects.json +++ b/packages/backend/test/fixtures/projects.json @@ -10,8 +10,8 @@ "framework": "test", "webhooks": [], "icon": "", - "registryRecordId": "hbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationDeploymentRequestId": "hbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationDeploymentRequestData": {}, "subDomain": "testProject.snowball.xyz" }, { @@ -25,8 +25,8 @@ "framework": "test-2", "webhooks": [], "icon": "", - "registryRecordId": "gbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationDeploymentRequestId": "gbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationDeploymentRequestData": {}, "subDomain": "testProject-2.snowball.xyz" }, { @@ -40,8 +40,8 @@ "framework": "test-3", "webhooks": [], "icon": "", - "registryRecordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationDeploymentRequestId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationDeploymentRequestData": {}, "subDomain": "iglootools.snowball.xyz" }, { @@ -55,8 +55,8 @@ "framework": "test-4", "webhooks": [], "icon": "", - "registryRecordId": "qbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationDeploymentRequestId": "qbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationDeploymentRequestData": {}, "subDomain": "iglootools-2.snowball.xyz" }, { @@ -70,8 +70,8 @@ "framework": "test-5", "webhooks": [], "icon": "", - "registryRecordId": "xbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", - "registryRecordData": {}, + "applicationDeploymentRequestId": "xbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", + "applicationDeploymentRequestData": {}, "subDomain": "snowball-2.snowball.xyz" } ] diff --git a/packages/backend/test/publish-deploy-records.ts b/packages/backend/test/publish-deploy-records.ts index 6f2d26b0..f5636c4e 100644 --- a/packages/backend/test/publish-deploy-records.ts +++ b/packages/backend/test/publish-deploy-records.ts @@ -41,8 +41,8 @@ async function main () { const applicationDeploymentRecord = { type: 'ApplicationDeploymentRecord', version: '0.0.1', - name: deployment.registryRecordData.name, - application: deployment.registryRecordId, + name: deployment.applicationRecordData.name, + application: deployment.applicationRecordId, // TODO: Create DNS record dns: 'bafyreihlymqggsgqiqawvehkpr2imt4l3u6q7um7xzjrux5rhsvwnuyewm', @@ -53,7 +53,7 @@ async function main () { so: '66fcfa49a1664d4cb4ce4f72c1c0e151' }), - request: deployment.project.registryRecordId, + request: deployment.project.applicationDeploymentRequestId, url }; diff --git a/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx b/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx index 5add83f9..1121eb54 100644 --- a/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx +++ b/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx @@ -90,7 +90,9 @@ const DeploymentDetailsCard = ({
- {deployment.url} + {deployment.url && ( + {deployment.url} + )} - ^ Visit + ^ Visit setAssignDomainDialog(!assignDomainDialog)} diff --git a/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx b/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx index 65a5a4b6..e4388bf8 100644 --- a/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx +++ b/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx @@ -28,9 +28,11 @@ const DeploymentDialogBodyCard = ({ color={chip.color} /> )} - - {deployment.url} - + {deployment.url && ( + + {deployment.url} + + )} ^ {deployment.branch} ^{' '} {deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '} diff --git a/packages/gql-client/src/types.ts b/packages/gql-client/src/types.ts index e75d0aba..71c44c00 100644 --- a/packages/gql-client/src/types.ts +++ b/packages/gql-client/src/types.ts @@ -63,7 +63,7 @@ export type Deployment = { branch: string commitHash: string commitMessage: string - url: string + url?: string environment: Environment isCurrent: boolean status: DeploymentStatus