fix: prevent webhook deploy crash when commit data lacks modified files (#4470)

shouldDeploy passed undefined/null entries from commit.modified straight
into micromatch, which throws "Expected input to be a string" and fails
every webhook deployment when watch paths are configured. Filter out
non-string values before matching.
This commit is contained in:
Mauricio Siu
2026-05-22 16:46:26 -06:00
committed by GitHub
parent af8072d7ad
commit b06138b230
2 changed files with 46 additions and 2 deletions
@@ -0,0 +1,41 @@
import { shouldDeploy } from "@dokploy/server";
import { describe, expect, it } from "vitest";
describe("shouldDeploy", () => {
it("should deploy when no watch paths are configured", () => {
expect(shouldDeploy(null, ["src/index.ts"])).toBe(true);
expect(shouldDeploy([], ["src/index.ts"])).toBe(true);
});
it("should deploy when watch paths match modified files", () => {
expect(shouldDeploy(["src/**"], ["src/index.ts"])).toBe(true);
expect(shouldDeploy(["apps/web/**"], ["apps/web/page.tsx"])).toBe(true);
});
it("should not deploy when watch paths do not match", () => {
expect(shouldDeploy(["src/**"], ["docs/readme.md"])).toBe(false);
});
it("should not throw when modified files contain non-string values", () => {
expect(() =>
shouldDeploy(["src/**"], ["src/index.ts", undefined, null] as any),
).not.toThrow();
expect(
shouldDeploy(["src/**"], ["src/index.ts", undefined, null] as any),
).toBe(true);
});
it("should not throw when modified files are undefined or null", () => {
expect(() => shouldDeploy(["src/**"], undefined)).not.toThrow();
expect(() => shouldDeploy(["src/**"], null)).not.toThrow();
expect(shouldDeploy(["src/**"], undefined)).toBe(false);
expect(shouldDeploy(["src/**"], null)).toBe(false);
});
it("should not throw when every modified file is non-string", () => {
expect(() =>
shouldDeploy(["src/**"], [undefined, undefined] as any),
).not.toThrow();
expect(shouldDeploy(["src/**"], [undefined, undefined] as any)).toBe(false);
});
});
@@ -2,8 +2,11 @@ import micromatch from "micromatch";
export const shouldDeploy = ( export const shouldDeploy = (
watchPaths: string[] | null, watchPaths: string[] | null,
modifiedFiles: string[], modifiedFiles: (string | null | undefined)[] | null | undefined,
): boolean => { ): boolean => {
if (!watchPaths || watchPaths?.length === 0) return true; if (!watchPaths || watchPaths?.length === 0) return true;
return micromatch.some(modifiedFiles, watchPaths); const files = (modifiedFiles ?? []).filter(
(file): file is string => typeof file === "string",
);
return micromatch.some(files, watchPaths);
}; };