feat: integrate build server functionality and enhance deployment process

- Added support for build server configuration in the application dashboard, including new UI elements and validation.
- Updated database schema to include build server associations and foreign key constraints.
- Enhanced deployment logic to utilize build server IDs, improving deployment flexibility.
- Improved logging and user feedback during the build and deployment processes, including new alerts for image download status.
- Refactored application and deployment services to accommodate build server integration.
This commit is contained in:
Mauricio Siu
2025-11-29 23:04:02 -06:00
parent 704582f6de
commit 15634c9f10
13 changed files with 6946 additions and 43 deletions

View File

@@ -29,13 +29,14 @@ export type ApplicationNested = InferResultType<
redirects: true;
ports: true;
registry: true;
buildRegistry: true;
environment: { with: { project: true } };
}
>;
export const getBuildCommand = (application: ApplicationNested) => {
let command = "";
const { buildType, registry } = application;
const { buildType } = application;
if (application.sourceType === "docker") {
return "";
@@ -60,7 +61,7 @@ export const getBuildCommand = (application: ApplicationNested) => {
command = getRailpackCommand(application);
break;
}
if (registry) {
if (application.registry || application.buildRegistry) {
command += uploadImageRemoteCommand(application);
}
@@ -169,13 +170,15 @@ export const mechanizeDockerContainer = async (
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
},
});
} catch {
} catch (error) {
console.log(error);
await docker.createService(settings);
}
};
const getImageName = (application: ApplicationNested) => {
const { appName, sourceType, dockerImage, registry } = application;
const { appName, sourceType, dockerImage, registry, buildRegistry } =
application;
const imageName = `${appName}:latest`;
if (sourceType === "docker") {
return dockerImage || "ERROR-NO-IMAGE-PROVIDED";
@@ -188,12 +191,26 @@ const getImageName = (application: ApplicationNested) => {
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
return registryTag;
}
if (buildRegistry) {
const { registryUrl, imagePrefix, username } = buildRegistry;
const registryTag = imagePrefix
? `${registryUrl ? `${registryUrl}/` : ""}${imagePrefix}/${imageName}`
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
return registryTag;
}
return imageName;
};
export const getAuthConfig = (application: ApplicationNested) => {
const { registry, username, password, sourceType, registryUrl } = application;
const {
registry,
buildRegistry,
username,
password,
sourceType,
registryUrl,
} = application;
if (sourceType === "docker") {
if (username && password) {
@@ -209,6 +226,12 @@ export const getAuthConfig = (application: ApplicationNested) => {
username: registry.username,
serveraddress: registry.registryUrl,
};
} else if (buildRegistry) {
return {
password: buildRegistry.password,
username: buildRegistry.username,
serveraddress: buildRegistry.registryUrl,
};
}
return undefined;

View File

@@ -1,44 +1,77 @@
import type { Registry } from "@dokploy/server/services/registry";
import type { ApplicationNested } from "../builders";
export const uploadImageRemoteCommand = (application: ApplicationNested) => {
const registry = application.registry;
const buildRegistry = application.buildRegistry;
if (!registry) {
throw new Error("Registry not found");
if (!registry && !buildRegistry) {
throw new Error("No registry found");
}
const { registryUrl, imagePrefix, username } = registry;
const { appName } = application;
const imageName = `${appName}:latest`;
const finalURL = registryUrl;
// Build registry tag in correct format: registry.com/owner/image:tag
const registryTag = imagePrefix
? `${registryUrl ? `${registryUrl}/` : ""}${imagePrefix}/${imageName}`
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
const commands: string[] = [];
if (registry) {
const registryTag = getRegistryTag(registry, imageName);
if (registryTag) {
commands.push(`echo "📦 [Enabled Registry Swarm]"`);
commands.push(getRegistryCommands(registry, imageName, registryTag));
}
}
if (buildRegistry) {
const buildRegistryTag = getRegistryTag(buildRegistry, imageName);
if (buildRegistryTag) {
commands.push(`echo "🔑 [Enabled Build Registry]"`);
commands.push(
getRegistryCommands(buildRegistry, imageName, buildRegistryTag),
);
commands.push(
`echo "⚠️ INFO: After the build is finished, you need to wait a few seconds for the server to download the image and run the container."`,
);
commands.push(
`echo "📊 Check the Logs tab to see when the container starts running."`,
);
}
}
try {
const command = `
echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" ;
echo "${registry.password}" | docker login ${finalURL} -u ${registry.username} --password-stdin || {
echo "❌ DockerHub Failed" ;
exit 1;
}
echo "✅ Registry Login Success" ;
docker tag ${imageName} ${registryTag} || {
echo "❌ Error tagging image" ;
exit 1;
}
echo "✅ Image Tagged" ;
docker push ${registryTag} || {
echo "❌ Error pushing image" ;
exit 1;
}
echo "✅ Image Pushed" ;
`;
return command;
return commands.join("\n");
} catch (error) {
throw error;
}
};
const getRegistryTag = (registry: Registry | null, imageName: string) => {
if (!registry) {
return null;
}
const { registryUrl, imagePrefix, username } = registry;
return imagePrefix
? `${registryUrl ? `${registryUrl}/` : ""}${imagePrefix}/${imageName}`
: `${registryUrl ? `${registryUrl}/` : ""}${username}/${imageName}`;
};
const getRegistryCommands = (
registry: Registry,
imageName: string,
registryTag: string,
): string => {
return `
echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" ;
echo "${registry.password}" | docker login ${registry.registryUrl} -u ${registry.username} --password-stdin || {
echo "❌ DockerHub Failed" ;
exit 1;
}
echo "✅ Registry Login Success" ;
docker tag ${imageName} ${registryTag} || {
echo "❌ Error tagging image" ;
exit 1;
}
echo "✅ Image Tagged" ;
docker push ${registryTag} || {
echo "❌ Error pushing image" ;
exit 1;
}
echo "✅ Image Pushed" ;
`;
};