Publish ApplicationRecord and ApplicationDeploymentRequest on creating new deployments (#89)

* Create application deployment request on new deployment

* Save application deployment request datas in deployment entity

* Add project as dependency

* Use project repo name as record app name

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2024-02-22 10:04:33 +05:30 committed by GitHub
parent 4d0f2ca893
commit e816c596ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 78 additions and 68 deletions

View File

@ -26,6 +26,15 @@ export enum DeploymentStatus {
Error = 'Error', Error = 'Error',
} }
export interface ApplicationDeploymentRequest {
type: string
version: string
name: string
application: string
config: string,
meta: string
}
export interface ApplicationRecord { export interface ApplicationRecord {
type: string; type: string;
version:string version:string
@ -78,6 +87,12 @@ export class Deployment {
@Column('simple-json') @Column('simple-json')
applicationRecordData!: ApplicationRecord; applicationRecordData!: ApplicationRecord;
@Column('varchar')
applicationDeploymentRequestId!: string;
@Column('simple-json')
applicationDeploymentRequestData!: ApplicationDeploymentRequest;
@Column('varchar', { nullable: true }) @Column('varchar', { nullable: true })
applicationDeploymentRecordId!: string | null; applicationDeploymentRecordId!: string | null;

View File

@ -15,15 +15,6 @@ import { Organization } from './Organization';
import { ProjectMember } from './ProjectMember'; import { ProjectMember } from './ProjectMember';
import { Deployment } from './Deployment'; import { Deployment } from './Deployment';
export interface ApplicationDeploymentRequest {
type: string
version: string
name: string
application: string
config: string,
meta: string
}
@Entity() @Entity()
export class Project { export class Project {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
@ -52,12 +43,6 @@ export class Project {
@Column('varchar', { length: 255, default: 'main' }) @Column('varchar', { length: 255, default: 'main' })
prodBranch!: string; prodBranch!: string;
@Column('varchar', { nullable: true })
applicationDeploymentRequestId!: string | null;
@Column('simple-json', { nullable: true })
applicationDeploymentRequestData!: ApplicationDeploymentRequest | null;
@Column('text', { default: '' }) @Column('text', { default: '' })
description!: string; description!: string;

View File

@ -6,8 +6,7 @@ import { DateTime } from 'luxon';
import { Registry as LaconicRegistry } from '@cerc-io/laconic-sdk'; import { Registry as LaconicRegistry } from '@cerc-io/laconic-sdk';
import { RegistryConfig } from './config'; import { RegistryConfig } from './config';
import { ApplicationDeploymentRequest } from './entity/Project'; import { ApplicationRecord, Deployment, ApplicationDeploymentRequest } from './entity/Deployment';
import { ApplicationRecord, Deployment } from './entity/Deployment';
import { AppDeploymentRecord, PackageJSON } from './types'; import { AppDeploymentRecord, PackageJSON } from './types';
const log = debug('snowball:registry'); const log = debug('snowball:registry');
@ -27,17 +26,18 @@ export class Registry {
} }
async createApplicationRecord ({ async createApplicationRecord ({
appName,
packageJSON, packageJSON,
commitHash, commitHash,
appType, appType,
repoUrl repoUrl
}: { }: {
appName: string,
packageJSON: PackageJSON packageJSON: PackageJSON
commitHash: string, commitHash: string,
appType: string, appType: string,
repoUrl: string repoUrl: string
}): Promise<{applicationRecordId: string, applicationRecordData: ApplicationRecord}> { }): Promise<{applicationRecordId: string, applicationRecordData: ApplicationRecord}> {
assert(packageJSON.name, "name field doesn't exist in package.json");
// Use laconic-sdk to publish record // 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 // Reference: https://git.vdb.to/cerc-io/test-progressive-web-app/src/branch/main/scripts/publish-app-record.sh
// Fetch previous records // Fetch previous records
@ -60,7 +60,7 @@ export class Registry {
repository_ref: commitHash, repository_ref: commitHash,
repository: [repoUrl], repository: [repoUrl],
app_type: appType, app_type: appType,
name: packageJSON.name, name: appName,
...(packageJSON.description && { description: packageJSON.description }), ...(packageJSON.description && { description: packageJSON.description }),
...(packageJSON.homepage && { homepage: packageJSON.homepage }), ...(packageJSON.homepage && { homepage: packageJSON.homepage }),
...(packageJSON.license && { license: packageJSON.license }), ...(packageJSON.license && { license: packageJSON.license }),
@ -81,7 +81,7 @@ export class Registry {
log('Application record data:', applicationRecord); log('Application record data:', applicationRecord);
// TODO: Discuss computation of CRN // TODO: Discuss computation of CRN
const crn = this.getCrn(packageJSON.name); const crn = this.getCrn(packageJSON.name, appName);
log(`Setting name: ${crn} for record ID: ${result.data.id}`); log(`Setting name: ${crn} for record ID: ${result.data.id}`);
await this.registry.setName({ cid: result.data.id, crn }, this.registryConfig.privateKey, this.registryConfig.fee); await this.registry.setName({ cid: result.data.id, crn }, this.registryConfig.privateKey, this.registryConfig.fee);
@ -93,6 +93,7 @@ export class Registry {
async createApplicationDeploymentRequest (data: { async createApplicationDeploymentRequest (data: {
appName: string, appName: string,
packageJsonName: string,
commitHash: string, commitHash: string,
repository: string, repository: string,
environmentVariables: { [key: string]: string } environmentVariables: { [key: string]: string }
@ -100,7 +101,7 @@ export class Registry {
applicationDeploymentRequestId: string, applicationDeploymentRequestId: string,
applicationDeploymentRequestData: ApplicationDeploymentRequest applicationDeploymentRequestData: ApplicationDeploymentRequest
}> { }> {
const crn = this.getCrn(data.appName); const crn = this.getCrn(data.packageJsonName, data.appName);
const records = await this.registry.resolveNames([crn]); const records = await this.registry.resolveNames([crn]);
const applicationRecord = records[0]; const applicationRecord = records[0];
@ -159,14 +160,10 @@ export class Registry {
return records.filter((record: AppDeploymentRecord) => deployments.some(deployment => deployment.applicationRecordId === record.attributes.application)); return records.filter((record: AppDeploymentRecord) => deployments.some(deployment => deployment.applicationRecordId === record.attributes.application));
} }
getCrn (packageJsonName: string): string { getCrn (packageJsonName: string, appName: string): string {
const [arg1, arg2] = packageJsonName.split('/'); const [arg1] = packageJsonName.split('/');
const authority = arg1.replace('@', '');
if (arg2) { return `crn://${authority}/applications/${appName}`;
const authority = arg1.replace('@', '');
return `crn://${authority}/applications/${arg2}`;
}
return `crn://${arg1}/applications/${arg1}`;
} }
} }

View File

@ -15,7 +15,7 @@ import { Permission, ProjectMember } from './entity/ProjectMember';
import { User } from './entity/User'; import { User } from './entity/User';
import { Registry } from './registry'; import { Registry } from './registry';
import { GitHubConfig, RegistryConfig } from './config'; import { GitHubConfig, RegistryConfig } from './config';
import { AppDeploymentRecord, GitPushEventPayload } from './types'; import { AppDeploymentRecord, GitPushEventPayload, PackageJSON } from './types';
const log = debug('snowball:service'); const log = debug('snowball:service');
@ -326,7 +326,9 @@ export class Service {
} }
assert(!Array.isArray(packageJSONData) && packageJSONData.type === 'file'); assert(!Array.isArray(packageJSONData) && packageJSONData.type === 'file');
const packageJSON = JSON.parse(atob(packageJSONData.content)); const packageJSON: PackageJSON = JSON.parse(atob(packageJSONData.content));
assert(packageJSON.name, "name field doesn't exist in package.json");
if (!recordData.repoUrl) { if (!recordData.repoUrl) {
const { data: repoDetails } = await octokit.rest.repos.get({ owner, repo }); const { data: repoDetails } = await octokit.rest.repos.get({ owner, repo });
@ -335,12 +337,30 @@ export class Service {
// TODO: Set environment variables for each deployment (environment variables can`t be set in application record) // TODO: Set environment variables for each deployment (environment variables can`t be set in application record)
const { applicationRecordId, applicationRecordData } = await this.registry.createApplicationRecord({ const { applicationRecordId, applicationRecordData } = await this.registry.createApplicationRecord({
appName: repo,
packageJSON, packageJSON,
appType: data.project!.template!, appType: data.project!.template!,
commitHash: data.commitHash!, commitHash: data.commitHash!,
repoUrl: recordData.repoUrl repoUrl: recordData.repoUrl
}); });
const environmentVariables = await this.db.getEnvironmentVariablesByProjectId(data.project.id!, { environment: Environment.Production });
const environmentVariablesObj = environmentVariables.reduce((acc, env) => {
acc[env.key] = env.value;
return acc;
}, {} as { [key: string]: string });
const { applicationDeploymentRequestId, applicationDeploymentRequestData } = await this.registry.createApplicationDeploymentRequest(
{
appName: repo,
packageJsonName: packageJSON.name,
commitHash: data.commitHash!,
repository: recordData.repoUrl,
environmentVariables: environmentVariablesObj
});
// Update previous deployment with prod branch domain // Update previous deployment with prod branch domain
// TODO: Fix unique constraint error for domain // TODO: Fix unique constraint error for domain
await this.db.updateDeployment({ await this.db.updateDeployment({
@ -358,6 +378,8 @@ export class Service {
status: DeploymentStatus.Building, status: DeploymentStatus.Building,
applicationRecordId, applicationRecordId,
applicationRecordData, applicationRecordData,
applicationDeploymentRequestId,
applicationDeploymentRequestData,
domain: data.domain, domain: data.domain,
createdBy: Object.assign(new User(), { createdBy: Object.assign(new User(), {
id: userId id: userId
@ -393,7 +415,7 @@ export class Service {
const { data: repoDetails } = await octokit.rest.repos.get({ owner, repo }); const { data: repoDetails } = await octokit.rest.repos.get({ owner, repo });
// Create deployment with prod branch and latest commit // Create deployment with prod branch and latest commit
const newDeployment = await this.createDeployment(userId, await this.createDeployment(userId,
octokit, octokit,
{ {
project, project,
@ -408,27 +430,6 @@ export class Service {
} }
); );
const environmentVariables = await this.db.getEnvironmentVariablesByProjectId(project.id, { environment: Environment.Production });
const environmentVariablesObj = environmentVariables.reduce((acc, env) => {
acc[env.key] = env.value;
return acc;
}, {} as { [key: string]: string });
const { applicationDeploymentRequestId, applicationDeploymentRequestData } = await this.registry.createApplicationDeploymentRequest(
{
appName: newDeployment.applicationRecordData.name!,
commitHash: latestCommit.sha,
repository: repoDetails.html_url,
environmentVariables: environmentVariablesObj
});
await this.db.updateProjectById(project.id, {
applicationDeploymentRequestId,
applicationDeploymentRequestData
});
await this.createRepoHook(octokit, project); await this.createRepoHook(octokit, project);
return project; return project;

View File

@ -1,6 +1,6 @@
export interface PackageJSON { export interface PackageJSON {
name?: string; name: string;
version?: string; version: string;
author?: string; author?: string;
description?: string; description?: string;
homepage?: string; homepage?: string;

View File

@ -9,6 +9,8 @@
"isCurrent": true, "isCurrent": true,
"applicationRecordId": "qbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "qbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "xqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "main", "branch": "main",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -24,6 +26,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "wbafyreihvzya6ovp4yfpkqnddkui2iw7thbhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "wbafyreihvzya6ovp4yfpkqnddkui2iw7thbhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "wqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -39,6 +43,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "kqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -54,6 +60,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "rbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhw74lbqs7bhobvmfhrowoi", "applicationRecordId": "rbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhw74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "yqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "prod", "branch": "prod",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -69,6 +77,8 @@
"isCurrent": true, "isCurrent": true,
"applicationRecordId": "tbafyreihvzya6ovp4yfpqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "tbafyreihvzya6ovp4yfpqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "pqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "main", "branch": "main",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -84,6 +94,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "ybafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "ybafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "tqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -99,6 +111,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "ubafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvfhrowoi", "applicationRecordId": "ubafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "eqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -114,6 +128,8 @@
"isCurrent": true, "isCurrent": true,
"applicationRecordId": "ibayreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "ibayreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "dqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "main", "branch": "main",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -129,6 +145,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "obafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "applicationRecordId": "obafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "aqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -144,6 +162,8 @@
"isCurrent": false, "isCurrent": false,
"applicationRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", "applicationRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "uqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",
@ -159,6 +179,8 @@
"isCurrent": true, "isCurrent": true,
"applicationRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", "applicationRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo",
"applicationRecordData": {}, "applicationRecordData": {},
"applicationDeploymentRequestId": "pqbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"branch": "test", "branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added", "commitMessage": "subscription added",

View File

@ -10,8 +10,6 @@
"framework": "test", "framework": "test",
"webhooks": [], "webhooks": [],
"icon": "", "icon": "",
"applicationDeploymentRequestId": "hbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"subDomain": "testProject.snowball.xyz" "subDomain": "testProject.snowball.xyz"
}, },
{ {
@ -25,8 +23,6 @@
"framework": "test-2", "framework": "test-2",
"webhooks": [], "webhooks": [],
"icon": "", "icon": "",
"applicationDeploymentRequestId": "gbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"subDomain": "testProject-2.snowball.xyz" "subDomain": "testProject-2.snowball.xyz"
}, },
{ {
@ -40,8 +36,6 @@
"framework": "test-3", "framework": "test-3",
"webhooks": [], "webhooks": [],
"icon": "", "icon": "",
"applicationDeploymentRequestId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"subDomain": "iglootools.snowball.xyz" "subDomain": "iglootools.snowball.xyz"
}, },
{ {
@ -55,8 +49,6 @@
"framework": "test-4", "framework": "test-4",
"webhooks": [], "webhooks": [],
"icon": "", "icon": "",
"applicationDeploymentRequestId": "qbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"subDomain": "iglootools-2.snowball.xyz" "subDomain": "iglootools-2.snowball.xyz"
}, },
{ {
@ -70,8 +62,6 @@
"framework": "test-5", "framework": "test-5",
"webhooks": [], "webhooks": [],
"icon": "", "icon": "",
"applicationDeploymentRequestId": "xbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
"applicationDeploymentRequestData": {},
"subDomain": "snowball-2.snowball.xyz" "subDomain": "snowball-2.snowball.xyz"
} }
] ]

View File

@ -53,7 +53,7 @@ async function main () {
so: '66fcfa49a1664d4cb4ce4f72c1c0e151' so: '66fcfa49a1664d4cb4ce4f72c1c0e151'
}), }),
request: deployment.project.applicationDeploymentRequestId, request: deployment.applicationDeploymentRequestId,
url url
}; };

View File

@ -30,14 +30,14 @@ const DeploymentsTabPanel = () => {
const fetchDeployments = useCallback(async () => { const fetchDeployments = useCallback(async () => {
const { deployments } = await client.getDeployments(project.id); const { deployments } = await client.getDeployments(project.id);
setDeployments(deployments); setDeployments(deployments);
}, [client]); }, [client, project]);
const fetchProductionBranchDomains = useCallback(async () => { const fetchProductionBranchDomains = useCallback(async () => {
const { domains } = await client.getDomains(project.id, { const { domains } = await client.getDomains(project.id, {
branch: project.prodBranch, branch: project.prodBranch,
}); });
setProdBranchDomains(domains); setProdBranchDomains(domains);
}, [client]); }, [client, project]);
useEffect(() => { useEffect(() => {
fetchProductionBranchDomains(); fetchProductionBranchDomains();