initial production release 🎉

This commit is contained in:
Andras
2021-03-24 22:11:14 +01:00
commit dbe82b3e7c
101 changed files with 12479 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
const { verifyUserId, cleanupTmp, execShellAsync } = require('../../../../libs/common')
const Deployment = require('../../../../models/Deployment')
const { queueAndBuild } = require('../../../../libs/applications')
const { setDefaultConfiguration } = require('../../../../libs/applications/configuration')
const { docker } = require('../../../../libs/docker')
const cloneRepository = require('../../../../libs/applications/github/cloneRepository')
module.exports = async function (fastify) {
// const postSchema = {
// body: {
// type: "object",
// properties: {
// ref: { type: "string" },
// repository: {
// type: "object",
// properties: {
// id: { type: "number" },
// full_name: { type: "string" },
// },
// required: ["id", "full_name"],
// },
// installation: {
// type: "object",
// properties: {
// id: { type: "number" },
// },
// required: ["id"],
// },
// },
// required: ["ref", "repository", "installation"],
// },
// };
fastify.post('/', async (request, reply) => {
if (!await verifyUserId(request.headers.authorization)) {
reply.code(500).send({ error: 'Invalid request' })
return
}
const configuration = setDefaultConfiguration(request.body)
const services = (await docker.engine.listServices()).filter(r => r.Spec.Labels.managedBy === 'coolify' && r.Spec.Labels.type === 'application')
await cloneRepository(configuration)
let foundService = false
let foundDomain = false
let configChanged = false
let imageChanged = false
let forceUpdate = false
for (const service of services) {
const running = JSON.parse(service.Spec.Labels.configuration)
if (running) {
if (
running.publish.domain === configuration.publish.domain &&
running.repository.id !== configuration.repository.id
) {
foundDomain = true
}
if (running.repository.id === configuration.repository.id && running.repository.branch === configuration.repository.branch) {
const state = await execShellAsync(`docker stack ps ${running.build.container.name} --format '{{ json . }}'`)
const isError = state.split('\n').filter(n => n).map(s => JSON.parse(s)).filter(n => n.DesiredState !== 'Running')
if (isError.length > 0) forceUpdate = true
foundService = true
const runningWithoutContainer = JSON.parse(JSON.stringify(running))
delete runningWithoutContainer.build.container
const configurationWithoutContainer = JSON.parse(JSON.stringify(configuration))
delete configurationWithoutContainer.build.container
// If only the configuration changed
if (JSON.stringify(runningWithoutContainer.build) !== JSON.stringify(configurationWithoutContainer.build) || JSON.stringify(runningWithoutContainer.publish) !== JSON.stringify(configurationWithoutContainer.publish)) configChanged = true
// If only the image changed
if (running.build.container.tag !== configuration.build.container.tag) imageChanged = true
// If build pack changed, forceUpdate the service
if (running.build.pack !== configuration.build.pack) forceUpdate = true
}
}
}
if (foundDomain) {
cleanupTmp(configuration.general.workdir)
reply.code(500).send({ message: 'Domain already in use.' })
return
}
if (forceUpdate) {
imageChanged = false
configChanged = false
} else {
if (foundService && !imageChanged && !configChanged) {
cleanupTmp(configuration.general.workdir)
reply.code(500).send({ message: 'Nothing changed, no need to redeploy.' })
return
}
}
const alreadyQueued = await Deployment.find({
repoId: configuration.repository.id,
branch: configuration.repository.branch,
organization: configuration.repository.organization,
name: configuration.repository.name,
domain: configuration.publish.domain,
progress: { $in: ['queued', 'inprogress'] }
})
if (alreadyQueued.length > 0) {
reply.code(200).send({ message: 'Already in the queue.' })
return
}
queueAndBuild(configuration, services, configChanged, imageChanged)
reply.code(201).send({ message: 'Deployment queued.', nickname: configuration.general.nickname, name: configuration.build.container.name })
})
}

View File

@@ -0,0 +1,62 @@
const ApplicationLog = require('../../../../models/Logs/Application')
const Deployment = require('../../../../models/Deployment')
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const relativeTime = require('dayjs/plugin/relativeTime')
dayjs.extend(utc)
dayjs.extend(relativeTime)
module.exports = async function (fastify) {
const getLogSchema = {
querystring: {
type: 'object',
properties: {
repoId: { type: 'string' },
branch: { type: 'string' }
},
required: ['repoId', 'branch']
}
}
fastify.get('/', { schema: getLogSchema }, async (request, reply) => {
const { repoId, branch, page } = request.query
const onePage = 5
const show = Number(page) * onePage || 5
const deploy = await Deployment.find({ repoId, branch })
.select('-_id -__v -repoId')
.sort({ createdAt: 'desc' })
.limit(show)
const finalLogs = deploy.map(d => {
const finalLogs = { ...d._doc }
const updatedAt = dayjs(d.updatedAt).utc()
finalLogs.took = updatedAt.diff(dayjs(d.createdAt)) / 1000
finalLogs.since = updatedAt.fromNow()
return finalLogs
})
return finalLogs
})
fastify.get('/:deployId', async (request, reply) => {
const { deployId } = request.params
try {
const logs = await ApplicationLog.find({ deployId })
.select('-_id -__v')
.sort({ createdAt: 'asc' })
const deploy = await Deployment.findOne({ deployId })
.select('-_id -__v')
.sort({ createdAt: 'desc' })
const finalLogs = {}
finalLogs.progress = deploy.progress
finalLogs.events = logs.map(log => log.event)
finalLogs.human = dayjs(deploy.updatedAt).from(dayjs(deploy.updatedAt))
return finalLogs
} catch (e) {
throw new Error('No logs found')
}
})
}