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',
}
export interface ApplicationDeploymentRequest {
type: string
version: string
name: string
application: string
config: string,
meta: string
}
export interface ApplicationRecord {
type: string;
version:string
@ -78,6 +87,12 @@ export class Deployment {
@Column('simple-json')
applicationRecordData!: ApplicationRecord;
@Column('varchar')
applicationDeploymentRequestId!: string;
@Column('simple-json')
applicationDeploymentRequestData!: ApplicationDeploymentRequest;
@Column('varchar', { nullable: true })
applicationDeploymentRecordId!: string | null;

View File

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

View File

@ -6,8 +6,7 @@ import { DateTime } from 'luxon';
import { Registry as LaconicRegistry } from '@cerc-io/laconic-sdk';
import { RegistryConfig } from './config';
import { ApplicationDeploymentRequest } from './entity/Project';
import { ApplicationRecord, Deployment } from './entity/Deployment';
import { ApplicationRecord, Deployment, ApplicationDeploymentRequest } from './entity/Deployment';
import { AppDeploymentRecord, PackageJSON } from './types';
const log = debug('snowball:registry');
@ -27,17 +26,18 @@ export class Registry {
}
async createApplicationRecord ({
appName,
packageJSON,
commitHash,
appType,
repoUrl
}: {
appName: string,
packageJSON: PackageJSON
commitHash: string,
appType: string,
repoUrl: string
}): 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
// Fetch previous records
@ -60,7 +60,7 @@ export class Registry {
repository_ref: commitHash,
repository: [repoUrl],
app_type: appType,
name: packageJSON.name,
name: appName,
...(packageJSON.description && { description: packageJSON.description }),
...(packageJSON.homepage && { homepage: packageJSON.homepage }),
...(packageJSON.license && { license: packageJSON.license }),
@ -81,7 +81,7 @@ export class Registry {
log('Application record data:', applicationRecord);
// 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}`);
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: {
appName: string,
packageJsonName: string,
commitHash: string,
repository: string,
environmentVariables: { [key: string]: string }
@ -100,7 +101,7 @@ export class Registry {
applicationDeploymentRequestId: string,
applicationDeploymentRequestData: ApplicationDeploymentRequest
}> {
const crn = this.getCrn(data.appName);
const crn = this.getCrn(data.packageJsonName, data.appName);
const records = await this.registry.resolveNames([crn]);
const applicationRecord = records[0];
@ -159,14 +160,10 @@ export class Registry {
return records.filter((record: AppDeploymentRecord) => deployments.some(deployment => deployment.applicationRecordId === record.attributes.application));
}
getCrn (packageJsonName: string): string {
const [arg1, arg2] = packageJsonName.split('/');
if (arg2) {
getCrn (packageJsonName: string, appName: string): string {
const [arg1] = packageJsonName.split('/');
const authority = arg1.replace('@', '');
return `crn://${authority}/applications/${arg2}`;
}
return `crn://${arg1}/applications/${arg1}`;
return `crn://${authority}/applications/${appName}`;
}
}

View File

@ -15,7 +15,7 @@ import { Permission, ProjectMember } from './entity/ProjectMember';
import { User } from './entity/User';
import { Registry } from './registry';
import { GitHubConfig, RegistryConfig } from './config';
import { AppDeploymentRecord, GitPushEventPayload } from './types';
import { AppDeploymentRecord, GitPushEventPayload, PackageJSON } from './types';
const log = debug('snowball:service');
@ -326,7 +326,9 @@ export class Service {
}
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) {
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)
const { applicationRecordId, applicationRecordData } = await this.registry.createApplicationRecord({
appName: repo,
packageJSON,
appType: data.project!.template!,
commitHash: data.commitHash!,
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
// TODO: Fix unique constraint error for domain
await this.db.updateDeployment({
@ -358,6 +378,8 @@ export class Service {
status: DeploymentStatus.Building,
applicationRecordId,
applicationRecordData,
applicationDeploymentRequestId,
applicationDeploymentRequestData,
domain: data.domain,
createdBy: Object.assign(new User(), {
id: userId
@ -393,7 +415,7 @@ export class Service {
const { data: repoDetails } = await octokit.rest.repos.get({ owner, repo });
// Create deployment with prod branch and latest commit
const newDeployment = await this.createDeployment(userId,
await this.createDeployment(userId,
octokit,
{
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);
return project;

View File

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

View File

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

View File

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

View File

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

View File

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