Integrate SP auctions for app deployment #2

Merged
nabarun merged 42 commits from ng-integrate-auction into main 2024-10-18 12:37:01 +00:00
2 changed files with 117 additions and 83 deletions
Showing only changes of commit b58d9e6c21 - Show all commits

View File

@ -126,14 +126,20 @@ export class Registry {
await sleep(SLEEP_DURATION); await sleep(SLEEP_DURATION);
await this.registry.setName( await this.registry.setName(
{ cid: result.id, lrn }, {
cid: result.id,
lrn
},
this.registryConfig.privateKey, this.registryConfig.privateKey,
fee fee
); );
await sleep(SLEEP_DURATION); await sleep(SLEEP_DURATION);
await this.registry.setName( await this.registry.setName(
{ cid: result.id, lrn: `${lrn}@${applicationRecord.app_version}` }, {
cid: result.id,
lrn: `${lrn}@${applicationRecord.app_version}`
},
this.registryConfig.privateKey, this.registryConfig.privateKey,
fee fee
); );
@ -162,7 +168,6 @@ export class Registry {
): Promise<{ ): Promise<{
applicationDeploymentAuctionId: string; applicationDeploymentAuctionId: string;
}> { }> {
// TODO: If data.domain is present then call createDeployment (don't need auction)
assert(data.project?.repository, 'Project repository not found'); assert(data.project?.repository, 'Project repository not found');
const [owner, repo] = data.project.repository.split('/'); const [owner, repo] = data.project.repository.split('/');
@ -190,7 +195,7 @@ export class Registry {
).data.html_url; ).data.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 } =
await this.createApplicationRecord({ await this.createApplicationRecord({
appName: repo, appName: repo,
packageJSON, packageJSON,
@ -235,7 +240,7 @@ export class Registry {
// Create record of type applicationDeploymentAuction and publish // Create record of type applicationDeploymentAuction and publish
const applicationDeploymentAuction = { const applicationDeploymentAuction = {
application: `${lrn}@${applicationRecord.attributes.app_version}`, application: lrn,
auction: auctionResult.auction.id, auction: auctionResult.auction.id,
type: APP_DEPLOYMENT_AUCTION_RECORD_TYPE, type: APP_DEPLOYMENT_AUCTION_RECORD_TYPE,
}; };
@ -454,6 +459,11 @@ export class Registry {
return completedAuctions; return completedAuctions;
} }
async getRecordsByName(name: string): Promise<any> {
return this.registry.resolveNames([name]);
}
getLrn(appName: string): string { getLrn(appName: string): string {
assert(this.registryConfig.authority, "Authority doesn't exist"); assert(this.registryConfig.authority, "Authority doesn't exist");
return `lrn://${this.registryConfig.authority}/applications/${appName}`; return `lrn://${this.registryConfig.authority}/applications/${appName}`;

View File

@ -270,35 +270,28 @@ export class Service {
async checkAuctionStatus( async checkAuctionStatus(
): Promise<void> { ): Promise<void> {
// Deployment should be in building state and should not have domain. // Deployment should be in building state and should not have domain.
const deployments = await this.db.getDeployments({ const projects = await this.db.getProjects({
where: { where: {
status: DeploymentStatus.Building, deployerLrn: IsNull()
domain: IsNull()
}, },
}); });
// Check the auctionId for those deployments with auctions const auctionIds = projects
const auctionIds = deployments .map(project => project.auctionId) as string[];
.filter(deployment => deployment.project && deployment.project.auctionId)
.map(deployment => deployment.project!.auctionId) as string[];
// Get all the auctions for those ids with auction status completed // Get all the auctions for those ids with auction status completed
const completedAuctionIds = await this.registry.getCompletedAuctionIds(auctionIds); const completedAuctionIds = await this.registry.getCompletedAuctionIds(auctionIds);
// If the deplyer lrn array is empty then call createDeploymentFromAuction // If the deplyer lrn array is empty then call createDeploymentFromAuction
const auctionDeployments = deployments.filter(deployment => const auctionProjects = projects.filter(project =>
completedAuctionIds.includes(deployment.project!.auctionId!) && completedAuctionIds.includes(project.auctionId!)
deployment.project!.deployerLrn?.length === 0
); );
for (const auctionDeployment of auctionDeployments) { for (const project of auctionProjects) {
await this.createDeploymentFromAuction( await this.createDeploymentFromAuction(project);
'user id',
auctionDeployment.project!.auctionId!,
auctionDeployment
);
} }
this.deployRecordCheckTimeout = setTimeout(() => { this.deployRecordCheckTimeout = setTimeout(() => {
this.checkAuctionStatus(); this.checkAuctionStatus();
}, this.config.registryConfig.fetchDeploymentRecordDelay); }, this.config.registryConfig.checkAuctionStatusDelay);
} }
async getUser(userId: string): Promise<User | null> { async getUser(userId: string): Promise<User | null> {
@ -691,67 +684,103 @@ export class Service {
} }
async createDeploymentFromAuction( async createDeploymentFromAuction(
userId: string, project: DeepPartial<Project>,
auctionId: string,
// take project data
// project: DeepPartial<Project>,
data: DeepPartial<Deployment>,
) { ) {
// TODO: If data.domain is present then call createDeployment (don't need auction) const deployerLrns = await this.registry.getAuctionWinners(project!.auctionId!);
const newDeployment = await this.db.addDeployment({
project: data.project, // Update project with deployer LRNs
branch: data.branch, await this.db.updateProjectById(project.id!, {
commitHash: data.commitHash, deployerLrn: deployerLrns
commitMessage: data.commitMessage, })
environment: data.environment,
status: DeploymentStatus.Building, const octokit = await this.getOctokit(project.owner!.id!);
domain: data.domain, const [owner, repo] = project.repository!.split('/');
createdBy: Object.assign(new User(), {
id: userId, const repoUrl = (
}), await octokit.rest.repos.get({
owner,
repo,
})
).data.html_url;
const {
data: [latestCommit],
} = await octokit.rest.repos.listCommits({
owner,
repo,
sha: project.prodBranch,
per_page: 1,
}); });
log( const lrn = this.registry.getLrn(repo);
`Created deployment ${newDeployment.id}`, const [record] = await this.registry.getRecordsByName(lrn);
); const applicationRecordId = record.id;
const applicationRecordData = record.attributes;
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 },
);
// To set project DNS
if (data.environment === Environment.Production) {
// On deleting deployment later, project DNS deployment is also deleted
// So publish project DNS deployment first so that ApplicationDeploymentRecord for the same is available when deleting deployment later
await this.registry.createApplicationDeploymentRequest({
deployment: newDeployment,
appName: data.project!.name!,
repository: data.url!,
environmentVariables: environmentVariablesObj,
dns: `${newDeployment.project.name}`,
});
}
const deployerLrns = await this.registry.getAuctionWinners(auctionId);
for (const deployer in deployerLrns) { for (const deployer in deployerLrns) {
// Create deployment with prod branch and latest commit
const deploymentData = {
project,
branch: project.prodBranch,
environment: Environment.Production,
domain: null,
commitHash: latestCommit.sha,
commitMessage: latestCommit.commit.message,
};
const newDeployment = await this.db.addDeployment({
project: project,
branch: deploymentData.branch,
commitHash: deploymentData.commitHash,
commitMessage: deploymentData.commitMessage,
environment: deploymentData.environment,
status: DeploymentStatus.Building,
applicationRecordId,
applicationRecordData,
domain: deploymentData.domain,
createdBy: Object.assign(new User(), {
id: project.owner!.id!,
}),
});
log(
`Created deployment ${newDeployment.id} and published application record ${applicationRecordId}`,
);
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 },
);
// To set project DNS
if (deploymentData.environment === Environment.Production) {
// On deleting deployment later, project DNS deployment is also deleted
// So publish project DNS deployment first so that ApplicationDeploymentRecord for the same is available when deleting deployment later
await this.registry.createApplicationDeploymentRequest({
deployment: newDeployment,
appName: project.name!,
repository: repoUrl,
environmentVariables: environmentVariablesObj,
dns: `${newDeployment.project.name}`,
});
}
const { applicationDeploymentRequestId, applicationDeploymentRequestData } = const { applicationDeploymentRequestId, applicationDeploymentRequestData } =
// Create requests for all the deployers // Create requests for all the deployers
await this.registry.createApplicationDeploymentRequest({ await this.registry.createApplicationDeploymentRequest({
deployment: newDeployment, deployment: newDeployment,
appName: data.project!.name!, appName: project.name!,
repository: data.url!, repository: repoUrl,
auctionId, auctionId: project.auctionId!,
lrn: deployer, lrn: deployer,
environmentVariables: environmentVariablesObj, environmentVariables: environmentVariablesObj,
dns: `${newDeployment.project.name}-${newDeployment.id}`, dns: `${newDeployment.project.name}-${newDeployment.id}`,
@ -762,12 +791,6 @@ export class Service {
applicationDeploymentRequestData, applicationDeploymentRequestData,
}); });
} }
// update project with deployerlrns
await this.db.updateProjectById(data.project?.id!, {
deployerLrn: deployerLrns
})
} }
async addProjectFromTemplate( async addProjectFromTemplate(
@ -859,9 +882,10 @@ export class Service {
commitMessage: latestCommit.commit.message, commitMessage: latestCommit.commit.message,
}; };
const deployment = auctionData await (auctionData
? await this.registry.createApplicationDeploymentAuction(repo, octokit, auctionData!, deploymentData) ? this.registry.createApplicationDeploymentAuction(repo, octokit, auctionData!, deploymentData)
: await this.createDeployment(user.id, octokit, deploymentData, lrn); : this.createDeployment(user.id, octokit, deploymentData, lrn)
);
await this.createRepoHook(octokit, project); await this.createRepoHook(octokit, project);