mirror of
https://github.com/snowball-tools/snowballtools-base
synced 2025-08-10 07:44:06 +00:00
Add record data to project and deployment entity
This commit is contained in:
parent
2bce67ce87
commit
f7643d6638
@ -25,6 +25,20 @@ export enum DeploymentStatus {
|
||||
Error = 'Error',
|
||||
}
|
||||
|
||||
export interface ApplicationRecord {
|
||||
type: string;
|
||||
version:string
|
||||
name: string
|
||||
description: string
|
||||
homepage: string
|
||||
license: string
|
||||
author: string
|
||||
repository: string,
|
||||
app_version: string
|
||||
repository_ref: string
|
||||
app_type: string
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class Deployment {
|
||||
// TODO: set custom generated id
|
||||
@ -51,6 +65,9 @@ export class Deployment {
|
||||
@Column('varchar')
|
||||
recordId!: string;
|
||||
|
||||
@Column('simple-json')
|
||||
recordData!: ApplicationRecord;
|
||||
|
||||
@Column({
|
||||
enum: Environment
|
||||
})
|
||||
|
@ -15,6 +15,17 @@ import { Organization } from './Organization';
|
||||
import { ProjectMember } from './ProjectMember';
|
||||
import { Deployment } from './Deployment';
|
||||
|
||||
export interface ApplicationDeploymentRequest {
|
||||
type: string
|
||||
version: string
|
||||
name: string
|
||||
application: string
|
||||
config: {
|
||||
env: {[key:string]: string}
|
||||
},
|
||||
meta: {[key:string]: string}
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class Project {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
@ -43,6 +54,9 @@ export class Project {
|
||||
@Column('varchar')
|
||||
recordId!: string;
|
||||
|
||||
@Column('simple-json')
|
||||
recordData!: ApplicationDeploymentRequest;
|
||||
|
||||
@Column('text', { default: '' })
|
||||
description!: string;
|
||||
|
||||
|
@ -29,7 +29,7 @@ export const main = async (): Promise<void> => {
|
||||
const db = new Database(database);
|
||||
await db.init();
|
||||
|
||||
const registry = new Registry({ registryConfig });
|
||||
const registry = new Registry(registryConfig);
|
||||
const service = new Service(db, app, registry);
|
||||
|
||||
const typeDefs = fs.readFileSync(path.join(__dirname, 'schema.gql')).toString();
|
||||
|
@ -4,6 +4,8 @@ import { inc as semverInc } from 'semver';
|
||||
import { Registry as LaconicRegistry } from '@cerc-io/laconic-sdk';
|
||||
|
||||
import { RegistryConfig } from './config';
|
||||
import { ApplicationDeploymentRequest } from './entity/Project';
|
||||
import { ApplicationRecord } from './entity/Deployment';
|
||||
|
||||
const log = debug('snowball:registry');
|
||||
|
||||
@ -15,13 +17,12 @@ export class Registry {
|
||||
private registry: LaconicRegistry;
|
||||
private registryConfig: RegistryConfig;
|
||||
|
||||
constructor ({ registryConfig }: { registryConfig: RegistryConfig }) {
|
||||
constructor (registryConfig : RegistryConfig) {
|
||||
this.registryConfig = registryConfig;
|
||||
this.registry = new LaconicRegistry(registryConfig.gqlEndpoint, registryConfig.restEndpoint, registryConfig.chainId);
|
||||
}
|
||||
|
||||
// TODO: Create record called from create deployment
|
||||
async createApplicationRecord (data: { recordName: string }): Promise<string> {
|
||||
async createApplicationRecord (data: { recordName: string, appType: string }): Promise<{recordId: string, recordData: ApplicationRecord}> {
|
||||
// TODO: Get record name from repo package.json name
|
||||
const recordName = data.recordName;
|
||||
|
||||
@ -41,7 +42,7 @@ export class Registry {
|
||||
// Create record of type ApplicationRecord and publish
|
||||
const applicationRecord = {
|
||||
type: APP_RECORD_TYPE,
|
||||
version: nextVersion,
|
||||
version: nextVersion ?? '',
|
||||
name: recordName,
|
||||
|
||||
// TODO: Get data from repo package.json
|
||||
@ -54,9 +55,7 @@ export class Registry {
|
||||
|
||||
// TODO: Get latest commit hash from repo production branch / deployment
|
||||
repository_ref: '10ac6678e8372a05ad5bb1c34c34',
|
||||
|
||||
// TODO: Get from project framework/template type
|
||||
app_type: 'webapp'
|
||||
app_type: data.appType
|
||||
};
|
||||
|
||||
const result = await this.registry.setRecord(
|
||||
@ -69,22 +68,20 @@ export class Registry {
|
||||
this.registryConfig.fee
|
||||
);
|
||||
|
||||
// TODO: Log deployment id
|
||||
log(`Application record published for deployment: ${result.data.id}`);
|
||||
log('Application record data:', applicationRecord);
|
||||
|
||||
// TODO: Discuss computation of crn
|
||||
const crn = this.getCrn(AUTHORITY_NAME, data.recordName);
|
||||
const crn = this.getCrn(data.recordName);
|
||||
|
||||
await this.registry.setName({ cid: result.data.id, crn }, this.registryConfig.privateKey, this.registryConfig.fee);
|
||||
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 result.data.id;
|
||||
return { recordId: result.data.id, recordData: applicationRecord };
|
||||
}
|
||||
|
||||
async createApplicationDeploymentRequest (data: { appName: string }): Promise<string> {
|
||||
const crn = this.getCrn(AUTHORITY_NAME, data.appName);
|
||||
async createApplicationDeploymentRequest (data: { appName: string }): Promise<{recordId: string, recordData: ApplicationDeploymentRequest}> {
|
||||
const crn = this.getCrn(data.appName);
|
||||
const records = await this.registry.resolveNames([crn]);
|
||||
const applicationRecord = records[0];
|
||||
|
||||
@ -127,10 +124,10 @@ export class Registry {
|
||||
log(`Application deployment request record published: ${result.data.id}`);
|
||||
log('Application deployment request data:', applicationDeploymentRequest);
|
||||
|
||||
return result.data.id;
|
||||
return { recordId: result.data.id, recordData: applicationDeploymentRequest };
|
||||
}
|
||||
|
||||
getCrn (authority: string, appName: string): string {
|
||||
return `crn://${authority}/applications/${appName}`;
|
||||
getCrn (appName: string): string {
|
||||
return `crn://${AUTHORITY_NAME}/applications/${appName}`;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
redeployToProd: async (_: any, { deploymentId }: { deploymentId: string }, context: any) => {
|
||||
try {
|
||||
return await service.redeployToProd(context.userId, deploymentId);
|
||||
return Boolean(await service.redeployToProd(context.userId, deploymentId));
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
|
@ -132,6 +132,7 @@ input AddProjectInput {
|
||||
name: String!
|
||||
repository: String!
|
||||
prodBranch: String!
|
||||
template: String!
|
||||
}
|
||||
|
||||
input UpdateProjectInput {
|
||||
|
@ -12,6 +12,9 @@ import { Project } from './entity/Project';
|
||||
import { Permission, ProjectMember } from './entity/ProjectMember';
|
||||
import { User } from './entity/User';
|
||||
import { Registry } from './registry';
|
||||
import debug from 'debug';
|
||||
|
||||
const log = debug('snowball:service');
|
||||
|
||||
export class Service {
|
||||
private db: Database;
|
||||
@ -166,7 +169,7 @@ export class Service {
|
||||
const prodBranchDomains = await this.db.getDomainsByProjectId(oldDeployment.project.id, { branch: oldDeployment.project.prodBranch });
|
||||
|
||||
// TODO: Fix unique constraint error for domain
|
||||
const DeploymentWithProdBranchDomain = await this.db.getDeployment({
|
||||
const deploymentWithProdBranchDomain = await this.db.getDeployment({
|
||||
where: {
|
||||
domain: {
|
||||
id: prodBranchDomains[0].id
|
||||
@ -174,8 +177,8 @@ export class Service {
|
||||
}
|
||||
});
|
||||
|
||||
if (DeploymentWithProdBranchDomain) {
|
||||
await this.db.updateDeploymentById(DeploymentWithProdBranchDomain.id, {
|
||||
if (deploymentWithProdBranchDomain) {
|
||||
await this.db.updateDeploymentById(deploymentWithProdBranchDomain.id, {
|
||||
domain: null,
|
||||
isCurrent: false
|
||||
});
|
||||
@ -197,34 +200,41 @@ export class Service {
|
||||
await this.db.updateDeploymentById(oldCurrentDeployment.id, { isCurrent: false, domain: null });
|
||||
}
|
||||
|
||||
const newDeployement = await this.createDeployment({
|
||||
project: oldDeployment.project,
|
||||
userId,
|
||||
isCurrent: true,
|
||||
environment: Environment.Production,
|
||||
domain: prodBranchDomains[0],
|
||||
commitHash: oldDeployment.commitHash
|
||||
});
|
||||
const newDeployement = await this.createDeployment(userId,
|
||||
{
|
||||
project: oldDeployment.project,
|
||||
isCurrent: true,
|
||||
branch: oldDeployment.branch,
|
||||
environment: Environment.Production,
|
||||
domain: prodBranchDomains[0],
|
||||
commitHash: oldDeployment.commitHash
|
||||
});
|
||||
|
||||
return newDeployement;
|
||||
}
|
||||
|
||||
async createDeployment (data: { project: Project, userId: string, isCurrent: boolean, environment: Environment, domain?: Domain | null, commitHash: string }): Promise<Deployment> {
|
||||
const applicationRecordId = await this.registry.createApplicationRecord({ recordName: data.project.name });
|
||||
async createDeployment (userId: string, data: DeepPartial<Deployment>): Promise<Deployment> {
|
||||
const { recordId, recordData } = await this.registry.createApplicationRecord({
|
||||
recordName: data.project?.name ?? '',
|
||||
appType: data.project?.template ?? ''
|
||||
});
|
||||
|
||||
const newDeployement = await this.db.addDeployement({
|
||||
project: data.project,
|
||||
branch: data.project.prodBranch,
|
||||
branch: data.branch,
|
||||
commitHash: data.commitHash,
|
||||
environment: data.environment,
|
||||
isCurrent: data.isCurrent,
|
||||
status: DeploymentStatus.Building,
|
||||
recordId: applicationRecordId,
|
||||
recordId,
|
||||
recordData,
|
||||
domain: data.domain,
|
||||
createdBy: Object.assign(new User(), {
|
||||
id: data.userId
|
||||
id: userId
|
||||
})
|
||||
});
|
||||
|
||||
log(`Application record ${recordId} published for deployment ${newDeployement.id}`);
|
||||
return newDeployement;
|
||||
}
|
||||
|
||||
@ -240,22 +250,26 @@ export class Service {
|
||||
|
||||
const project = await this.db.addProject(userId, organization.id, {
|
||||
...data,
|
||||
recordId: ''
|
||||
recordId: '',
|
||||
recordData: {}
|
||||
});
|
||||
|
||||
// TODO: Get repository details from github
|
||||
await this.createDeployment({
|
||||
project,
|
||||
userId,
|
||||
isCurrent: true,
|
||||
environment: Environment.Production,
|
||||
// TODO: Set latest commit hash
|
||||
commitHash: ""
|
||||
});
|
||||
await this.createDeployment(userId,
|
||||
{
|
||||
project,
|
||||
isCurrent: true,
|
||||
branch: project.prodBranch,
|
||||
environment: Environment.Production,
|
||||
// TODO: Set latest commit hash
|
||||
commitHash: '',
|
||||
domain: null
|
||||
});
|
||||
|
||||
const applicationDeploymentRequestRecordId = await this.registry.createApplicationDeploymentRequest({ appName: project.name });
|
||||
const { recordId, recordData } = await this.registry.createApplicationDeploymentRequest({ appName: project.name });
|
||||
await this.db.updateProjectById(project.id, {
|
||||
recordId: applicationDeploymentRequestRecordId
|
||||
recordId,
|
||||
recordData
|
||||
});
|
||||
|
||||
return project;
|
||||
@ -283,7 +297,7 @@ export class Service {
|
||||
return this.db.deleteDomainById(domainId);
|
||||
}
|
||||
|
||||
async redeployToProd (userId: string, deploymentId: string): Promise<Deployment| boolean> {
|
||||
async redeployToProd (userId: string, deploymentId: string): Promise<Deployment> {
|
||||
const oldDeployment = await this.db.getDeployment({
|
||||
relations: {
|
||||
project: true,
|
||||
@ -299,19 +313,20 @@ export class Service {
|
||||
throw new Error('Deployment not found');
|
||||
}
|
||||
|
||||
const oldDeploymentUpdated = await this.db.updateDeploymentById(deploymentId, { domain: null, isCurrent: false });
|
||||
await this.db.updateDeploymentById(deploymentId, { domain: null, isCurrent: false });
|
||||
|
||||
const newDeployement = await this.createDeployment({
|
||||
project: oldDeployment.project,
|
||||
userId: userId,
|
||||
// TODO: Put isCurrent field in project
|
||||
isCurrent: true,
|
||||
environment: Environment.Production,
|
||||
domain: oldDeployment.domain,
|
||||
commitHash: oldDeployment.commitHash
|
||||
});
|
||||
const newDeployement = await this.createDeployment(userId,
|
||||
{
|
||||
project: oldDeployment.project,
|
||||
// TODO: Put isCurrent field in project
|
||||
branch: oldDeployment.branch,
|
||||
isCurrent: true,
|
||||
environment: Environment.Production,
|
||||
domain: oldDeployment.domain,
|
||||
commitHash: oldDeployment.commitHash
|
||||
});
|
||||
|
||||
return oldDeploymentUpdated && Boolean(newDeployement);
|
||||
return newDeployement;
|
||||
}
|
||||
|
||||
async rollbackDeployment (projectId: string, deploymentId: string): Promise<boolean> {
|
||||
|
10
packages/backend/test/fixtures/deployments.json
vendored
10
packages/backend/test/fixtures/deployments.json
vendored
@ -8,6 +8,7 @@
|
||||
"environment": "Production",
|
||||
"isCurrent": true,
|
||||
"recordId": "qbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "main",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-ffhae3zq.snowball.xyz"
|
||||
@ -21,6 +22,7 @@
|
||||
"environment": "Preview",
|
||||
"isCurrent": false,
|
||||
"recordId": "wbafyreihvzya6ovp4yfpkqnddkui2iw7thbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "test",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-vehagei8.snowball.xyz"
|
||||
@ -34,6 +36,7 @@
|
||||
"environment": "Development",
|
||||
"isCurrent": false,
|
||||
"recordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "test",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-qmgekyte.snowball.xyz"
|
||||
@ -47,6 +50,7 @@
|
||||
"environment": "Production",
|
||||
"isCurrent": false,
|
||||
"recordId": "rbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhw74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "prod",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-f8wsyim6.snowball.xyz"
|
||||
@ -60,6 +64,7 @@
|
||||
"environment": "Production",
|
||||
"isCurrent": true,
|
||||
"recordId": "tbafyreihvzya6ovp4yfpqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "main",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-2-eO8cckxk.snowball.xyz"
|
||||
@ -73,6 +78,7 @@
|
||||
"environment": "Preview",
|
||||
"isCurrent": false,
|
||||
"recordId": "ybafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "test",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-2-yaq0t5yw.snowball.xyz"
|
||||
@ -86,6 +92,7 @@
|
||||
"environment": "Development",
|
||||
"isCurrent": false,
|
||||
"recordId": "ubafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "test",
|
||||
"commitHash": "testXyz",
|
||||
"url": "testProject-2-hwwr6sbx.snowball.xyz"
|
||||
@ -99,6 +106,7 @@
|
||||
"environment": "Production",
|
||||
"isCurrent": true,
|
||||
"recordId": "ibayreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "main",
|
||||
"commitHash": "testXyz",
|
||||
"url": "iglootools-ndxje48a.snowball.xyz"
|
||||
@ -112,6 +120,7 @@
|
||||
"environment": "Preview",
|
||||
"isCurrent": false,
|
||||
"recordId": "obafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"branch": "test",
|
||||
"commitHash": "testXyz",
|
||||
"url": "iglootools-gtgpgvei.snowball.xyz"
|
||||
@ -125,6 +134,7 @@
|
||||
"environment": "Development",
|
||||
"isCurrent": false,
|
||||
"recordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo",
|
||||
"recordData": {},
|
||||
"branch": "test",
|
||||
"commitHash": "testXyz",
|
||||
"url": "iglootools-b4bpthjr.snowball.xyz"
|
||||
|
5
packages/backend/test/fixtures/projects.json
vendored
5
packages/backend/test/fixtures/projects.json
vendored
@ -11,6 +11,7 @@
|
||||
"webhooks": [],
|
||||
"icon": "",
|
||||
"recordId": "hbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"subDomain": "testProject.snowball.xyz"
|
||||
},
|
||||
{
|
||||
@ -25,6 +26,7 @@
|
||||
"webhooks": [],
|
||||
"icon": "",
|
||||
"recordId": "gbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"subDomain": "testProject-2.snowball.xyz"
|
||||
},
|
||||
{
|
||||
@ -39,6 +41,7 @@
|
||||
"webhooks": [],
|
||||
"icon": "",
|
||||
"recordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"subDomain": "iglootools.snowball.xyz"
|
||||
},
|
||||
{
|
||||
@ -53,6 +56,7 @@
|
||||
"webhooks": [],
|
||||
"icon": "",
|
||||
"recordId": "qbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"subDomain": "iglootools-2.snowball.xyz"
|
||||
},
|
||||
{
|
||||
@ -67,6 +71,7 @@
|
||||
"webhooks": [],
|
||||
"icon": "",
|
||||
"recordId": "xbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi",
|
||||
"recordData": {},
|
||||
"subDomain": "snowball-2.snowball.xyz"
|
||||
}
|
||||
]
|
||||
|
@ -26,6 +26,8 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
|
||||
name: `${repository.owner!.login}-${repository.name}`,
|
||||
prodBranch: repository.default_branch!,
|
||||
repository: repository.full_name,
|
||||
// TODO: Compute template from repo
|
||||
template: 'webapp',
|
||||
});
|
||||
|
||||
navigate(`import?projectId=${addProject.id}`);
|
||||
|
@ -52,6 +52,8 @@ const CreateRepo = () => {
|
||||
name: `${gitRepo.data.owner!.login}-${gitRepo.data.name}`,
|
||||
prodBranch: gitRepo.data.default_branch ?? 'main',
|
||||
repository: gitRepo.data.full_name,
|
||||
// TODO: Set selected template
|
||||
template: 'webapp',
|
||||
});
|
||||
|
||||
navigate(
|
||||
|
@ -243,6 +243,7 @@ export type AddProjectInput = {
|
||||
name: string;
|
||||
repository: string;
|
||||
prodBranch: string;
|
||||
template: string;
|
||||
}
|
||||
|
||||
export type UpdateProjectInput = {
|
||||
|
Loading…
Reference in New Issue
Block a user