Assign project domain to latest production deployment (#145)

* Create ApplicationDeploymentRequest with project DNS

* Add comment for filtering AppDeploymentRecord

* Fix lint

* Handle delete gitHub event

* Add sleep before registry write methods

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2024-02-29 18:33:34 +05:30 committed by GitHub
parent a7810a34c9
commit 1ff5ab3dfd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 25 deletions

View File

@ -12,12 +12,14 @@ import {
ApplicationDeploymentRequest ApplicationDeploymentRequest
} from './entity/Deployment'; } from './entity/Deployment';
import { AppDeploymentRecord, PackageJSON } from './types'; import { AppDeploymentRecord, PackageJSON } from './types';
import { sleep } from './utils';
const log = debug('snowball:registry'); const log = debug('snowball:registry');
const APP_RECORD_TYPE = 'ApplicationRecord'; const APP_RECORD_TYPE = 'ApplicationRecord';
const APP_DEPLOYMENT_REQUEST_TYPE = 'ApplicationDeploymentRequest'; const APP_DEPLOYMENT_REQUEST_TYPE = 'ApplicationDeploymentRequest';
const APP_DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRecord'; const APP_DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRecord';
const SLEEP_DURATION = 1000;
// TODO: Move registry code to laconic-sdk/watcher-ts // TODO: Move registry code to laconic-sdk/watcher-ts
export class Registry { export class Registry {
@ -111,16 +113,21 @@ export class Registry {
const crn = this.getCrn(appName); const crn = this.getCrn(appName);
log(`Setting name: ${crn} for record ID: ${result.data.id}`); log(`Setting name: ${crn} for record ID: ${result.data.id}`);
await sleep(SLEEP_DURATION);
await this.registry.setName( await this.registry.setName(
{ cid: result.data.id, crn }, { cid: result.data.id, crn },
this.registryConfig.privateKey, this.registryConfig.privateKey,
this.registryConfig.fee this.registryConfig.fee
); );
await sleep(SLEEP_DURATION);
await this.registry.setName( await this.registry.setName(
{ cid: result.data.id, crn: `${crn}@${applicationRecord.app_version}` }, { cid: result.data.id, crn: `${crn}@${applicationRecord.app_version}` },
this.registryConfig.privateKey, this.registryConfig.privateKey,
this.registryConfig.fee this.registryConfig.fee
); );
await sleep(SLEEP_DURATION);
await this.registry.setName( await this.registry.setName(
{ {
cid: result.data.id, cid: result.data.id,
@ -139,9 +146,9 @@ export class Registry {
async createApplicationDeploymentRequest (data: { async createApplicationDeploymentRequest (data: {
deployment: Deployment, deployment: Deployment,
appName: string, appName: string,
packageJsonName: string,
repository: string, repository: string,
environmentVariables: { [key: string]: string } environmentVariables: { [key: string]: string },
dns: string,
}): Promise<{ }): Promise<{
applicationDeploymentRequestId: string; applicationDeploymentRequestId: string;
applicationDeploymentRequestData: ApplicationDeploymentRequest; applicationDeploymentRequestData: ApplicationDeploymentRequest;
@ -160,7 +167,7 @@ export class Registry {
version: '1.0.0', version: '1.0.0',
name: `${applicationRecord.attributes.name}@${applicationRecord.attributes.app_version}`, name: `${applicationRecord.attributes.name}@${applicationRecord.attributes.app_version}`,
application: `${crn}@${applicationRecord.attributes.app_version}`, application: `${crn}@${applicationRecord.attributes.app_version}`,
dns: `${data.deployment.project.name}-${data.deployment.id}`, dns: data.dns,
// TODO: Not set in test-progressive-web-app CI // TODO: Not set in test-progressive-web-app CI
// deployment: '$CERC_REGISTRY_DEPLOYMENT_CRN', // deployment: '$CERC_REGISTRY_DEPLOYMENT_CRN',
@ -178,6 +185,7 @@ export class Registry {
}) })
}; };
await sleep(SLEEP_DURATION);
const result = await this.registry.setRecord( const result = await this.registry.setRecord(
{ {
privateKey: this.registryConfig.privateKey, privateKey: this.registryConfig.privateKey,
@ -211,11 +219,12 @@ export class Registry {
true true
); );
// Filter records with ApplicationRecord ids // Filter records with ApplicationRecord ID and Deployment specific URL
return records.filter((record: AppDeploymentRecord) => return records.filter((record: AppDeploymentRecord) =>
deployments.some( deployments.some(
(deployment) => (deployment) =>
deployment.applicationRecordId === record.attributes.application deployment.applicationRecordId === record.attributes.application &&
record.attributes.url.includes(deployment.id)
) )
); );
} }

View File

@ -382,8 +382,7 @@ export class Service {
async createDeployment ( async createDeployment (
userId: string, userId: string,
octokit: Octokit, octokit: Octokit,
data: DeepPartial<Deployment>, data: DeepPartial<Deployment>
recordData: { repoUrl?: string } = {}
): Promise<Deployment> { ): Promise<Deployment> {
assert(data.project?.repository, 'Project repository not found'); assert(data.project?.repository, 'Project repository not found');
log( log(
@ -407,13 +406,10 @@ export class Service {
assert(packageJSON.name, "name field doesn't exist in package.json"); assert(packageJSON.name, "name field doesn't exist in package.json");
if (!recordData.repoUrl) { const repoUrl = (await octokit.rest.repos.get({
const { data: repoDetails } = await octokit.rest.repos.get({
owner, owner,
repo repo
}); })).data.html_url;
recordData.repoUrl = repoDetails.html_url;
}
// 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 } = const { applicationRecordId, applicationRecordData } =
@ -422,7 +418,7 @@ export class Service {
packageJSON, packageJSON,
appType: data.project!.template!, appType: data.project!.template!,
commitHash: data.commitHash!, commitHash: data.commitHash!,
repoUrl: recordData.repoUrl repoUrl
}); });
// Update previous deployment with prod branch domain // Update previous deployment with prod branch domain
@ -464,11 +460,23 @@ export class Service {
{ {
deployment: newDeployment, deployment: newDeployment,
appName: repo, appName: repo,
packageJsonName: packageJSON.name, repository: repoUrl,
repository: recordData.repoUrl, environmentVariables: environmentVariablesObj,
environmentVariables: environmentVariablesObj dns: `${newDeployment.project.name}-${newDeployment.id}`
}); });
// To set project DNS
if (data.environment === Environment.Production) {
await this.registry.createApplicationDeploymentRequest(
{
deployment: newDeployment,
appName: repo,
repository: repoUrl,
environmentVariables: environmentVariablesObj,
dns: `${newDeployment.project.name}`
});
}
await this.db.updateDeploymentById(newDeployment.id, { applicationDeploymentRequestId, applicationDeploymentRequestData }); await this.db.updateDeploymentById(newDeployment.id, { applicationDeploymentRequestId, applicationDeploymentRequestData });
return newDeployment; return newDeployment;
@ -498,8 +506,6 @@ export class Service {
per_page: 1 per_page: 1
}); });
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
await this.createDeployment(user.id, await this.createDeployment(user.id,
octokit, octokit,
@ -510,9 +516,6 @@ export class Service {
domain: null, domain: null,
commitHash: latestCommit.sha, commitHash: latestCommit.sha,
commitMessage: latestCommit.commit.message commitMessage: latestCommit.commit.message
},
{
repoUrl: repoDetails.html_url
} }
); );
@ -555,8 +558,14 @@ export class Service {
} }
async handleGitHubPush (data: GitPushEventPayload): Promise<void> { async handleGitHubPush (data: GitPushEventPayload): Promise<void> {
const { repository, ref, head_commit: headCommit } = data; const { repository, ref, head_commit: headCommit, deleted } = data;
log(`Handling GitHub push event from repository: ${repository.full_name}`);
if (deleted) {
log(`Branch ${ref} deleted for project ${repository.full_name}`);
return;
}
log(`Handling GitHub push event from repository: ${repository.full_name}, branch: ${ref}`);
const projects = await this.db.getProjects({ const projects = await this.db.getProjects({
where: { repository: repository.full_name } where: { repository: repository.full_name }
}); });

View File

@ -24,6 +24,7 @@ export interface GitPushEventPayload {
id: string; id: string;
message: string; message: string;
}; };
deleted: boolean;
} }
export interface AppDeploymentRecordAttributes { export interface AppDeploymentRecordAttributes {

View File

@ -66,3 +66,5 @@ export const loadAndSaveData = async <Entity extends ObjectLiteral>(
return savedEntity; return savedEntity;
}; };
export const sleep = async (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));