forked from cerc-io/snowballtools-base
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -22,6 +22,7 @@ export interface RegistryConfig {
|
||||
chainId: string;
|
||||
privateKey: string;
|
||||
bondId: string;
|
||||
fetchDeploymentRecordDelay: number;
|
||||
fee: {
|
||||
amount: string;
|
||||
denom: string;
|
||||
|
||||
@@ -126,10 +126,18 @@ export class Database {
|
||||
return projects;
|
||||
}
|
||||
|
||||
async getDeploymentsByProjectId (projectId: string): Promise<Deployment[]> {
|
||||
/**
|
||||
* Get deployments with specified filter
|
||||
*/
|
||||
async getDeployments (options: FindManyOptions<Deployment>): Promise<Deployment[]> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
const deployments = await deploymentRepository.find(options);
|
||||
|
||||
const deployments = await deploymentRepository.find({
|
||||
return deployments;
|
||||
}
|
||||
|
||||
async getDeploymentsByProjectId (projectId: string): Promise<Deployment[]> {
|
||||
return this.getDeployments({
|
||||
relations: {
|
||||
project: true,
|
||||
domain: true,
|
||||
@@ -144,8 +152,6 @@ export class Database {
|
||||
createdAt: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
return deployments;
|
||||
}
|
||||
|
||||
async getDeployment (options: FindOneOptions<Deployment>): Promise<Deployment | null> {
|
||||
@@ -162,16 +168,14 @@ export class Database {
|
||||
return domains;
|
||||
}
|
||||
|
||||
async addDeployement (data: DeepPartial<Deployment>): Promise<Deployment> {
|
||||
async addDeployment (data: DeepPartial<Deployment>): Promise<Deployment> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
|
||||
const id = nanoid();
|
||||
const url = `${data.project!.name}-${id}.${PROJECT_DOMAIN}`;
|
||||
|
||||
const updatedData = {
|
||||
...data,
|
||||
id,
|
||||
url
|
||||
id
|
||||
};
|
||||
const deployment = await deploymentRepository.save(updatedData);
|
||||
|
||||
@@ -312,6 +316,19 @@ export class Database {
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
|
||||
async updateDeploymentsByProjectIds (projectIds: string[], data: DeepPartial<Deployment>): Promise<boolean> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
|
||||
const updateResult = await deploymentRepository
|
||||
.createQueryBuilder()
|
||||
.update(Deployment)
|
||||
.set(data)
|
||||
.where('projectId IN (:...projectIds)', { projectIds })
|
||||
.execute();
|
||||
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
|
||||
async addProject (userId: string, organizationId: string, data: DeepPartial<Project>): Promise<Project> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
|
||||
|
||||
@@ -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',
|
||||
@@ -28,7 +29,7 @@ export enum DeploymentStatus {
|
||||
export interface ApplicationRecord {
|
||||
type: string;
|
||||
version:string
|
||||
name?: string
|
||||
name: string
|
||||
description?: string
|
||||
homepage?: string
|
||||
license?: string
|
||||
@@ -45,6 +46,9 @@ export class Deployment {
|
||||
@PrimaryColumn('varchar')
|
||||
id!: string;
|
||||
|
||||
@Column()
|
||||
projectId!: string;
|
||||
|
||||
@ManyToOne(() => Project, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'projectId' })
|
||||
project!: Project;
|
||||
@@ -65,14 +69,20 @@ export class Deployment {
|
||||
@Column('varchar')
|
||||
commitMessage!: string;
|
||||
|
||||
@Column('varchar')
|
||||
url!: string;
|
||||
@Column('varchar', { nullable: true })
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -31,7 +31,7 @@ export const main = async (): Promise<void> => {
|
||||
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);
|
||||
|
||||
@@ -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,8 @@ 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
|
||||
// Fetch previous records
|
||||
@@ -58,7 +60,7 @@ export class Registry {
|
||||
repository_ref: commitHash,
|
||||
repository: [repoUrl],
|
||||
app_type: appType,
|
||||
...(packageJSON.name && { name: packageJSON.name }),
|
||||
name: packageJSON.name,
|
||||
...(packageJSON.description && { description: packageJSON.description }),
|
||||
...(packageJSON.homepage && { homepage: packageJSON.homepage }),
|
||||
...(packageJSON.license && { license: packageJSON.license }),
|
||||
@@ -79,14 +81,14 @@ 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);
|
||||
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: `${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: {
|
||||
@@ -95,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]);
|
||||
@@ -108,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}`,
|
||||
@@ -140,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<AppDeploymentRecord[]> {
|
||||
// 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 {
|
||||
|
||||
@@ -30,7 +30,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
},
|
||||
|
||||
deployments: async (_: any, { projectId }: { projectId: string }) => {
|
||||
return service.getDeployementsByProjectId(projectId);
|
||||
return service.getDeploymentsByProjectId(projectId);
|
||||
},
|
||||
|
||||
environmentVariables: async (_: any, { projectId }: { projectId: string }) => {
|
||||
|
||||
@@ -91,7 +91,7 @@ type Deployment {
|
||||
branch: String!
|
||||
commitHash: String!
|
||||
commitMessage: String!
|
||||
url: String!
|
||||
url: String
|
||||
environment: Environment!
|
||||
isCurrent: Boolean!
|
||||
status: DeploymentStatus!
|
||||
|
||||
+121
-34
@@ -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,112 @@ 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<void> {
|
||||
// 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
|
||||
if (records.length) {
|
||||
await this.updateDeploymentsWithRecordData(records);
|
||||
}
|
||||
}
|
||||
|
||||
this.deployRecordCheckTimeout = setTimeout(() => {
|
||||
this.checkDeployRecordsAndUpdate();
|
||||
}, this.config.registryConfig.fetchDeploymentRecordDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update deployments with ApplicationDeploymentRecord data
|
||||
*/
|
||||
async updateDeploymentsWithRecordData (records: AppDeploymentRecord[]): Promise<void> {
|
||||
// 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<string> => {
|
||||
if (deployment.environment === Environment.Production) {
|
||||
acc.add(deployment.projectId);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, new Set<string>());
|
||||
|
||||
// Set old deployments isCurrent to false
|
||||
await this.db.updateDeploymentsByProjectIds(Array.from(productionDeploymentProjectIds), { 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.id} with URL ${record.attributes.url}`);
|
||||
});
|
||||
|
||||
await Promise.all(deploymentUpdatePromises);
|
||||
}
|
||||
|
||||
async getUser (userId: string): Promise<User | null> {
|
||||
@@ -67,7 +170,7 @@ export class Service {
|
||||
return dbProjects;
|
||||
}
|
||||
|
||||
async getDeployementsByProjectId (projectId: string): Promise<Deployment[]> {
|
||||
async getDeploymentsByProjectId (projectId: string): Promise<Deployment[]> {
|
||||
const dbDeployments = await this.db.getDeploymentsByProjectId(projectId);
|
||||
return dbDeployments;
|
||||
}
|
||||
@@ -187,11 +290,10 @@ 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,
|
||||
isCurrent: true,
|
||||
branch: oldDeployment.branch,
|
||||
environment: Environment.Production,
|
||||
domain: prodBranchDomains[0],
|
||||
@@ -199,7 +301,7 @@ export class Service {
|
||||
commitMessage: oldDeployment.commitMessage
|
||||
});
|
||||
|
||||
return newDeployement;
|
||||
return newDeployment;
|
||||
}
|
||||
|
||||
async createDeployment (
|
||||
@@ -232,24 +334,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,24 +349,23 @@ 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,
|
||||
commitMessage: data.commitMessage,
|
||||
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<Project>): Promise<Project | undefined> {
|
||||
@@ -307,7 +397,6 @@ export class Service {
|
||||
octokit,
|
||||
{
|
||||
project,
|
||||
isCurrent: true,
|
||||
branch: project.prodBranch,
|
||||
environment: Environment.Production,
|
||||
domain: null,
|
||||
@@ -327,17 +416,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);
|
||||
@@ -393,7 +482,6 @@ export class Service {
|
||||
octokit,
|
||||
{
|
||||
project,
|
||||
isCurrent: project.prodBranch === branch,
|
||||
branch,
|
||||
environment: project.prodBranch === branch ? Environment.Production : Environment.Preview,
|
||||
domain,
|
||||
@@ -444,20 +532,19 @@ 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,
|
||||
// TODO: Put isCurrent field in project
|
||||
branch: oldDeployment.branch,
|
||||
isCurrent: true,
|
||||
environment: Environment.Production,
|
||||
domain: oldDeployment.domain,
|
||||
commitHash: oldDeployment.commitHash,
|
||||
commitMessage: oldDeployment.commitMessage
|
||||
});
|
||||
|
||||
return newDeployement;
|
||||
return newDeployment;
|
||||
}
|
||||
|
||||
async rollbackDeployment (projectId: string, deploymentId: string): Promise<boolean> {
|
||||
@@ -475,7 +562,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 });
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user