Integrate SP auctions for app deployment #2
@ -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}`;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user