Merge pull request #5455 from roshanasingh4/codex/preserve-app-status-on-provider-save

fix: preserve application status when saving provider settings
This commit is contained in:
Narciso E. Núñez Arias
2026-09-29 09:51:29 -04:00
committed by GitHub
2 changed files with 156 additions and 7 deletions
@@ -0,0 +1,156 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const mockUpdateApplication = vi.hoisted(() => vi.fn());
vi.mock("@dokploy/server/services/permission", () => {
return {
checkServicePermissionAndAccess: vi.fn(async () => undefined),
};
});
vi.mock("@dokploy/server/index", () => ({
IS_CLOUD: true,
hasValidLicense: vi.fn(async () => false),
updateApplication: mockUpdateApplication,
findApplicationById: vi.fn(async () => ({
applicationId: "app-1",
appName: "example-app",
})),
}));
vi.mock("@dokploy/server/lib/auth", () => ({
validateRequest: vi.fn(),
}));
vi.mock("@/server/api/utils/audit", () => ({
audit: vi.fn(async () => undefined),
}));
const { applicationRouter } = await import("@/server/api/routers/application");
const caller = applicationRouter.createCaller({
session: { activeOrganizationId: "org-1" },
user: { id: "user-1", email: "user@example.com", role: "owner" },
} as Parameters<typeof applicationRouter.createCaller>[0]);
const providerChanges = [
{
name: "GitHub",
sourceType: "github",
save: () =>
caller.saveGithubProvider({
applicationId: "app-1",
repository: "example-repo",
owner: "example-owner",
branch: "main",
buildPath: "/",
githubId: "provider-1",
watchPaths: ["src/**"],
triggerType: "push",
enableSubmodules: false,
}),
},
{
name: "GitLab",
sourceType: "gitlab",
save: () =>
caller.saveGitlabProvider({
applicationId: "app-1",
gitlabRepository: "example-repo",
gitlabOwner: "example-owner",
gitlabBranch: "main",
gitlabBuildPath: "/",
gitlabId: "provider-1",
gitlabProjectId: 1,
gitlabPathNamespace: "example-owner/example-repo",
}),
},
{
name: "Bitbucket",
sourceType: "bitbucket",
save: () =>
caller.saveBitbucketProvider({
applicationId: "app-1",
bitbucketRepository: "example-repo",
bitbucketRepositorySlug: "example-repo",
bitbucketOwner: "example-owner",
bitbucketBranch: "main",
bitbucketBuildPath: "/",
bitbucketId: "provider-1",
}),
},
{
name: "Gitea",
sourceType: "gitea",
save: () =>
caller.saveGiteaProvider({
applicationId: "app-1",
giteaRepository: "example-repo",
giteaOwner: "example-owner",
giteaBranch: "main",
giteaBuildPath: "/",
giteaId: "provider-1",
}),
},
{
name: "Docker",
sourceType: "docker",
save: () =>
caller.saveDockerProvider({
applicationId: "app-1",
dockerImage: "nginx:alpine",
username: "",
password: "",
registryUrl: "",
}),
},
{
name: "custom Git",
sourceType: "git",
save: () =>
caller.saveGitProvider({
applicationId: "app-1",
customGitUrl: "https://example.com/repo.git",
customGitBranch: "main",
customGitBuildPath: "/",
customGitSSHKeyId: "key-1",
watchPaths: ["src/**"],
enableSubmodules: false,
}),
},
{
name: "disconnect Git provider",
sourceType: "github",
save: () => caller.disconnectGitProvider({ applicationId: "app-1" }),
},
];
describe("saving an application provider", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it.each(providerChanges)(
"keeps the status when $name settings change",
async ({ save, sourceType }) => {
for (const status of ["done", "running"]) {
mockUpdateApplication.mockClear();
let savedStatus = status;
mockUpdateApplication.mockImplementation(async (_id, update) => {
if (update.applicationStatus !== undefined) {
savedStatus = update.applicationStatus;
}
});
await save();
expect(savedStatus).toBe(status);
expect(mockUpdateApplication).toHaveBeenCalledTimes(1);
expect(mockUpdateApplication).toHaveBeenCalledWith(
"app-1",
expect.objectContaining({ sourceType }),
);
}
},
);
});
@@ -545,7 +545,6 @@ export const applicationRouter = createTRPCRouter({
sourceType: "github",
owner: input.owner,
buildPath: input.buildPath,
applicationStatus: "idle",
githubId: input.githubId,
watchPaths: input.watchPaths,
triggerType: input.triggerType,
@@ -572,7 +571,6 @@ export const applicationRouter = createTRPCRouter({
gitlabBranch: input.gitlabBranch,
gitlabBuildPath: input.gitlabBuildPath,
sourceType: "gitlab",
applicationStatus: "idle",
gitlabId: input.gitlabId,
gitlabProjectId: input.gitlabProjectId,
gitlabPathNamespace: input.gitlabPathNamespace,
@@ -601,7 +599,6 @@ export const applicationRouter = createTRPCRouter({
bitbucketBranch: input.bitbucketBranch,
bitbucketBuildPath: input.bitbucketBuildPath,
sourceType: "bitbucket",
applicationStatus: "idle",
bitbucketId: input.bitbucketId,
watchPaths: input.watchPaths,
enableSubmodules: input.enableSubmodules,
@@ -627,7 +624,6 @@ export const applicationRouter = createTRPCRouter({
giteaBranch: input.giteaBranch,
giteaBuildPath: input.giteaBuildPath,
sourceType: "gitea",
applicationStatus: "idle",
giteaId: input.giteaId,
watchPaths: input.watchPaths,
enableSubmodules: input.enableSubmodules,
@@ -652,7 +648,6 @@ export const applicationRouter = createTRPCRouter({
username: input.username,
password: input.password,
sourceType: "docker",
applicationStatus: "idle",
registryUrl: input.registryUrl,
});
const application = await findApplicationById(input.applicationId);
@@ -676,7 +671,6 @@ export const applicationRouter = createTRPCRouter({
customGitUrl: input.customGitUrl,
customGitSSHKeyId: input.customGitSSHKeyId,
sourceType: "git",
applicationStatus: "idle",
watchPaths: input.watchPaths,
enableSubmodules: input.enableSubmodules,
});
@@ -729,7 +723,6 @@ export const applicationRouter = createTRPCRouter({
customGitSSHKeyId: null,
sourceType: "github", // Reset to default
applicationStatus: "idle",
watchPaths: null,
enableSubmodules: false,
});