2024-02-12 06:04:01 +00:00
|
|
|
import debug from 'debug';
|
|
|
|
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');
|
|
|
|
|
|
|
|
const APP_RECORD_TYPE = 'ApplicationRecord';
|
|
|
|
const DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRequest';
|
|
|
|
const AUTHORITY_NAME = 'snowball';
|
|
|
|
|
2024-02-12 09:48:00 +00:00
|
|
|
// TODO: Move registry code to laconic-sdk/watcher-ts
|
2024-02-12 06:04:01 +00:00
|
|
|
export class Registry {
|
|
|
|
private registry: LaconicRegistry;
|
|
|
|
private registryConfig: RegistryConfig;
|
|
|
|
|
|
|
|
constructor (registryConfig : RegistryConfig) {
|
|
|
|
this.registryConfig = registryConfig;
|
|
|
|
this.registry = new LaconicRegistry(registryConfig.gqlEndpoint, registryConfig.restEndpoint, registryConfig.chainId);
|
|
|
|
}
|
|
|
|
|
2024-02-12 09:48:00 +00:00
|
|
|
async createApplicationRecord (data: { recordName: string, appType: string }): Promise<{registryRecordId: string, registryRecordData: ApplicationRecord}> {
|
2024-02-12 06:04:01 +00:00
|
|
|
// TODO: Get record name from repo package.json name
|
|
|
|
const recordName = data.recordName;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
const records = await this.registry.queryRecords({
|
|
|
|
type: APP_RECORD_TYPE,
|
|
|
|
name: recordName
|
|
|
|
}, true);
|
|
|
|
|
|
|
|
// Get next version of record
|
|
|
|
const bondRecords = records.filter((record: any) => record.bondId === this.registryConfig.bondId);
|
|
|
|
const [latestBondRecord] = bondRecords.sort((a: any, b: any) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime());
|
|
|
|
const nextVersion = semverInc(latestBondRecord?.attributes.version ?? '0.0.0', 'patch');
|
|
|
|
|
|
|
|
// Create record of type ApplicationRecord and publish
|
|
|
|
const applicationRecord = {
|
|
|
|
type: APP_RECORD_TYPE,
|
|
|
|
version: nextVersion ?? '',
|
|
|
|
name: recordName,
|
|
|
|
|
|
|
|
// TODO: Get data from repo package.json
|
|
|
|
description: '',
|
|
|
|
homepage: '',
|
|
|
|
license: '',
|
|
|
|
author: '',
|
|
|
|
repository: '',
|
|
|
|
app_version: '0.1.0',
|
|
|
|
|
|
|
|
// TODO: Get latest commit hash from repo production branch / deployment
|
|
|
|
repository_ref: '10ac6678e8372a05ad5bb1c34c34',
|
|
|
|
app_type: data.appType
|
|
|
|
};
|
|
|
|
|
|
|
|
const result = await this.registry.setRecord(
|
|
|
|
{
|
|
|
|
privateKey: this.registryConfig.privateKey,
|
|
|
|
record: applicationRecord,
|
|
|
|
bondId: this.registryConfig.bondId
|
|
|
|
},
|
|
|
|
'',
|
|
|
|
this.registryConfig.fee
|
|
|
|
);
|
|
|
|
|
|
|
|
log('Application record data:', applicationRecord);
|
|
|
|
|
|
|
|
// TODO: Discuss computation of crn
|
|
|
|
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);
|
|
|
|
|
2024-02-12 09:48:00 +00:00
|
|
|
return { registryRecordId: result.data.id, registryRecordData: applicationRecord };
|
2024-02-12 06:04:01 +00:00
|
|
|
}
|
|
|
|
|
2024-02-12 09:48:00 +00:00
|
|
|
async createApplicationDeploymentRequest (data: { appName: string }): Promise<{registryRecordId: string, registryRecordData: ApplicationDeploymentRequest}> {
|
2024-02-12 06:04:01 +00:00
|
|
|
const crn = this.getCrn(data.appName);
|
|
|
|
const records = await this.registry.resolveNames([crn]);
|
|
|
|
const applicationRecord = records[0];
|
|
|
|
|
|
|
|
if (!applicationRecord) {
|
|
|
|
throw new Error(`No record found for ${crn}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create record of type ApplicationDeploymentRequest and publish
|
|
|
|
const applicationDeploymentRequest = {
|
|
|
|
type: DEPLOYMENT_RECORD_TYPE,
|
|
|
|
version: '1.0.0',
|
|
|
|
name: `${applicationRecord.attributes.name}@${applicationRecord.attributes.app_version}`,
|
|
|
|
application: `${crn}@${applicationRecord.attributes.app_version}`,
|
|
|
|
|
|
|
|
// TODO: Not set in test-progressive-web-app CI
|
|
|
|
// dns: '$CERC_REGISTRY_DEPLOYMENT_SHORT_HOSTNAME',
|
|
|
|
// deployment: '$CERC_REGISTRY_DEPLOYMENT_CRN',
|
|
|
|
|
|
|
|
config: {
|
|
|
|
env: {
|
|
|
|
CERC_WEBAPP_DEBUG: `${applicationRecord.attributes.app_version}`
|
|
|
|
}
|
|
|
|
},
|
|
|
|
meta: {
|
|
|
|
note: `Added by Snowball @ ${(new Date()).toISOString()}`,
|
|
|
|
repository: applicationRecord.attributes.repository,
|
|
|
|
repository_ref: applicationRecord.attributes.repository_ref
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const result = await this.registry.setRecord(
|
|
|
|
{
|
|
|
|
privateKey: this.registryConfig.privateKey,
|
|
|
|
record: applicationDeploymentRequest,
|
|
|
|
bondId: this.registryConfig.bondId
|
|
|
|
},
|
|
|
|
'',
|
|
|
|
this.registryConfig.fee
|
|
|
|
);
|
|
|
|
log(`Application deployment request record published: ${result.data.id}`);
|
|
|
|
log('Application deployment request data:', applicationDeploymentRequest);
|
|
|
|
|
2024-02-12 09:48:00 +00:00
|
|
|
return { registryRecordId: result.data.id, registryRecordData: applicationDeploymentRequest };
|
2024-02-12 06:04:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getCrn (appName: string): string {
|
|
|
|
return `crn://${AUTHORITY_NAME}/applications/${appName}`;
|
|
|
|
}
|
|
|
|
}
|