Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions apps/dokploy/__test__/deploy/builders-commit-info.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import { describe, expect, it } from "vitest";

import { getDockerCommand } from "@dokploy/server/utils/builders/docker-file";
import { getHerokuCommand } from "@dokploy/server/utils/builders/heroku";
import { getNixpacksCommand } from "@dokploy/server/utils/builders/nixpacks";
import { getPaketoCommand } from "@dokploy/server/utils/builders/paketo";
import { getRailpackCommand } from "@dokploy/server/utils/builders/railpack";
import {
getCommitInfoBuildArgs,
getCommitInfoEnvArgs,
getGitCommitInfoCommands,
} from "@dokploy/server/utils/builders/utils";
import type { ApplicationNested } from "@dokploy/server/utils/builders";

const createMockApplication = (overrides = {}): ApplicationNested =>
({
appName: "test-app",
buildType: "dockerfile" as const,
env: null,
buildArgs: null,
buildSecrets: null,
cleanCache: false,
environment: {
env: "",
project: { env: "" },
},
...overrides,
}) as unknown as ApplicationNested;

describe("Git Commit Info Helpers", () => {
it("getGitCommitInfoCommands should return shell commands to extract commit info", () => {
const commands = getGitCommitInfoCommands();
expect(commands).toContain(
"DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD",
);
expect(commands).toContain("DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD");
expect(commands).toContain(
"DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s",
);
expect(commands).toContain('|| echo "unknown"');
});

it("getCommitInfoBuildArgs should return --build-arg flags", () => {
const args = getCommitInfoBuildArgs();
expect(args).toContain(
'--build-arg DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
expect(args).toContain(
'--build-arg DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(args).toContain(
'--build-arg DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});

it("getCommitInfoEnvArgs should return --env flags", () => {
const args = getCommitInfoEnvArgs();
expect(args).toContain('--env DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"');
expect(args).toContain(
'--env DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(args).toContain(
'--env DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});
});

describe("Dockerfile builder - commit info injection", () => {
it("should include git commit info extraction commands", () => {
const command = getDockerCommand(createMockApplication());
expect(command).toContain(
"DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD",
);
expect(command).toContain("DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD");
expect(command).toContain(
"DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s",
);
});

it("should pass commit info as --build-arg to docker build", () => {
const command = getDockerCommand(createMockApplication());
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});

it("should include commit info alongside user-defined build args", () => {
const command = getDockerCommand(
createMockApplication({ buildArgs: "MY_VAR=hello" }),
);
expect(command).toContain("--build-arg MY_VAR");
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
});
});

describe("Nixpacks builder - commit info injection", () => {
it("should include git commit info extraction commands", () => {
const command = getNixpacksCommand(
createMockApplication({ buildType: "nixpacks" }),
);
expect(command).toContain(
"DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD",
);
expect(command).toContain("DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD");
expect(command).toContain(
"DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s",
);
});

it("should pass commit info as --env to nixpacks build", () => {
const command = getNixpacksCommand(
createMockApplication({ buildType: "nixpacks" }),
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});
});

describe("Heroku builder - commit info injection", () => {
it("should include git commit info extraction commands", () => {
const command = getHerokuCommand(
createMockApplication({ buildType: "heroku_buildpacks" }),
);
expect(command).toContain(
"DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD",
);
expect(command).toContain("DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD");
expect(command).toContain(
"DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s",
);
});

it("should pass commit info as --env to pack build", () => {
const command = getHerokuCommand(
createMockApplication({ buildType: "heroku_buildpacks" }),
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});
});

describe("Paketo builder - commit info injection", () => {
it("should include git commit info extraction commands", () => {
const command = getPaketoCommand(
createMockApplication({ buildType: "paketo_buildpacks" }),
);
expect(command).toContain(
"DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD",
);
expect(command).toContain("DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD");
expect(command).toContain(
"DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s",
);
});

it("should pass commit info as --env to pack build", () => {
const command = getPaketoCommand(
createMockApplication({ buildType: "paketo_buildpacks" }),
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(command).toContain(
'--env DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});
});

describe("Railpack builder - commit info injection", () => {
it("should include git commit info extraction commands", () => {
const command = getRailpackCommand(
createMockApplication({ buildType: "railpack" }),
);
expect(command).toContain(
"DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD",
);
expect(command).toContain("DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD");
expect(command).toContain(
"DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s",
);
});

it("should pass commit info as --build-arg to docker buildx", () => {
const command = getRailpackCommand(
createMockApplication({ buildType: "railpack" }),
);
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH"',
);
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT"',
);
expect(command).toContain(
'--build-arg DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"',
);
});
});
12 changes: 9 additions & 3 deletions packages/server/src/utils/builders/docker-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
getDockerContextPath,
} from "../filesystem/directory";
import type { ApplicationNested } from ".";
import { createEnvFileCommand } from "./utils";
import {
createEnvFileCommand,
getCommitInfoBuildArgs,
getGitCommitInfoCommands,
} from "./utils";

export const getDockerCommand = (application: ApplicationNested) => {
const {
Expand Down Expand Up @@ -86,12 +90,14 @@ export const getDockerCommand = (application: ApplicationNested) => {

command += `
echo "Building ${appName}" ;
cd ${dockerContextPath} || {
cd ${dockerContextPath} || {
echo "❌ The path ${dockerContextPath} does not exist" ;
exit 1;
}

${joinedSecrets} docker ${commandArgs.join(" ")} || {
${getGitCommitInfoCommands()}

${joinedSecrets} docker ${commandArgs.join(" ")} ${getCommitInfoBuildArgs()} || {
echo "❌ Docker build failed" ;
exit 1;
}
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/utils/builders/heroku.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { prepareEnvironmentVariablesForShell } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";
import type { ApplicationNested } from ".";
import { getCommitInfoEnvArgs, getGitCommitInfoCommands } from "./utils";

export const getHerokuCommand = (application: ApplicationNested) => {
const { env, appName, cleanCache } = application;
Expand Down Expand Up @@ -31,8 +32,9 @@ export const getHerokuCommand = (application: ApplicationNested) => {

const command = `pack ${args.join(" ")}`;
const bashCommand = `
${getGitCommitInfoCommands()}
echo "Starting heroku build..." ;
${command} || {
${command} ${getCommitInfoEnvArgs()} || {
echo "❌ Heroku build failed" ;
exit 1;
}
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/utils/builders/nixpacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { nanoid } from "nanoid";
import { prepareEnvironmentVariablesForShell } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";
import type { ApplicationNested } from ".";
import { getCommitInfoEnvArgs, getGitCommitInfoCommands } from "./utils";

export const getNixpacksCommand = (application: ApplicationNested) => {
const { env, appName, publishDirectory, cleanCache } = application;
Expand Down Expand Up @@ -32,8 +33,9 @@ export const getNixpacksCommand = (application: ApplicationNested) => {
}
const command = `nixpacks ${args.join(" ")}`;
let bashCommand = `
${getGitCommitInfoCommands()}
echo "Starting nixpacks build..." ;
${command} || {
${command} ${getCommitInfoEnvArgs()} || {
echo "❌ Nixpacks build failed" ;
exit 1;
}
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/utils/builders/paketo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { prepareEnvironmentVariablesForShell } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";
import type { ApplicationNested } from ".";
import { getCommitInfoEnvArgs, getGitCommitInfoCommands } from "./utils";

export const getPaketoCommand = (application: ApplicationNested) => {
const { env, appName, cleanCache } = application;
Expand Down Expand Up @@ -31,8 +32,9 @@ export const getPaketoCommand = (application: ApplicationNested) => {

const command = `pack ${args.join(" ")}`;
const bashCommand = `
${getGitCommitInfoCommands()}
echo "Starting Paketo build..." ;
${command} || {
${command} ${getCommitInfoEnvArgs()} || {
echo "❌ Paketo build failed" ;
exit 1;
}
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/utils/builders/railpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";
import type { ApplicationNested } from ".";
import { getCommitInfoBuildArgs, getGitCommitInfoCommands } from "./utils";

const calculateSecretsHash = (envVariables: string[]): string => {
const hash = createHash("sha256");
Expand Down Expand Up @@ -102,7 +103,8 @@ echo "✅ Railpack prepare completed." ;
echo "Building with Railpack frontend..." ;
# Export environment variables for secrets
${exportEnvs.join("\n")}
docker ${buildArgs.join(" ")} || {
${getGitCommitInfoCommands()}
docker ${buildArgs.join(" ")} ${getCommitInfoBuildArgs()} || {
echo "❌ Railpack build failed" ;
docker buildx rm builder-containerd || true
exit 1;
Expand Down
24 changes: 24 additions & 0 deletions packages/server/src/utils/builders/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,27 @@ export const createEnvFileCommand = (

return `echo "${encodedContent}" | base64 -d > "${envFilePath}";`;
};

/**
* Returns shell commands to extract git commit hash and message
* into DOKPLOY_COMMIT_HASH, DOKPLOY_COMMIT_SHORT, and DOKPLOY_COMMIT_MESSAGE shell variables.
*/
export const getGitCommitInfoCommands = () => {
return `DOKPLOY_COMMIT_HASH=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
DOKPLOY_COMMIT_SHORT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
DOKPLOY_COMMIT_MESSAGE=$(git log -1 --pretty=%s 2>/dev/null || echo "unknown")`;
};

/**
* Returns docker --build-arg flags for commit info.
*/
export const getCommitInfoBuildArgs = () => {
return '--build-arg DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH" --build-arg DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT" --build-arg DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"';
};

/**
* Returns --env flags for commit info (for pack/nixpacks builders).
*/
export const getCommitInfoEnvArgs = () => {
return '--env DOKPLOY_COMMIT_HASH="$DOKPLOY_COMMIT_HASH" --env DOKPLOY_COMMIT_SHORT="$DOKPLOY_COMMIT_SHORT" --env DOKPLOY_COMMIT_MESSAGE="$DOKPLOY_COMMIT_MESSAGE"';
};
Loading