Merge pull request #400 from iksaku/feat/docker-build-stage

feat(docker): Multi-stage Builds
This commit is contained in:
Mauricio Siu
2024-09-02 00:09:20 -06:00
committed by GitHub
8 changed files with 3593 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ const baseApp: ApplicationNested = {
appName: "", appName: "",
autoDeploy: true, autoDeploy: true,
branch: null, branch: null,
dockerBuildStage: "",
buildArgs: null, buildArgs: null,
buildPath: "/", buildPath: "/",
gitlabPathNamespace: "", gitlabPathNamespace: "",

View File

@@ -37,6 +37,7 @@ const mySchema = z.discriminatedUnion("buildType", [
}) })
.min(1, "Dockerfile required"), .min(1, "Dockerfile required"),
dockerContextPath: z.string().nullable().default(""), dockerContextPath: z.string().nullable().default(""),
dockerBuildStage: z.string().nullable().default(""),
}), }),
z.object({ z.object({
buildType: z.literal("heroku_buildpacks"), buildType: z.literal("heroku_buildpacks"),
@@ -86,6 +87,7 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
...(data.buildType && { ...(data.buildType && {
dockerfile: data.dockerfile || "", dockerfile: data.dockerfile || "",
dockerContextPath: data.dockerContextPath || "", dockerContextPath: data.dockerContextPath || "",
dockerBuildStage: data.dockerBuildStage || "",
}), }),
}); });
} else { } else {
@@ -106,6 +108,8 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
dockerfile: data.buildType === "dockerfile" ? data.dockerfile : null, dockerfile: data.buildType === "dockerfile" ? data.dockerfile : null,
dockerContextPath: dockerContextPath:
data.buildType === "dockerfile" ? data.dockerContextPath : null, data.buildType === "dockerfile" ? data.dockerContextPath : null,
dockerBuildStage:
data.buildType === "dockerfile" ? data.dockerBuildStage : null,
}) })
.then(async () => { .then(async () => {
toast.success("Build type saved"); toast.success("Build type saved");
@@ -241,6 +245,32 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
); );
}} }}
/> />
<FormField
control={form.control}
name="dockerBuildStage"
render={({ field }) => {
return (
<FormItem>
<div className="space-y-0.5">
<FormLabel>Docker Build Stage</FormLabel>
<FormDescription>
Allows you to target a specific stage in a
Multi-stage Dockerfile. If empty, Docker defaults to
build the last defined stage.
</FormDescription>
</div>
<FormControl>
<Input
placeholder={"E.g. production"}
{...field}
value={field.value ?? ""}
/>
</FormControl>
</FormItem>
);
}}
/>
</> </>
)} )}

View File

@@ -0,0 +1 @@
ALTER TABLE "application" ADD COLUMN "dockerBuildStage" text;

File diff suppressed because it is too large Load Diff

View File

@@ -239,6 +239,13 @@
"when": 1725250322137, "when": 1725250322137,
"tag": "0033_white_hawkeye", "tag": "0033_white_hawkeye",
"breakpoints": true "breakpoints": true
},
{
"idx": 34,
"version": "6",
"when": 1725256397019,
"tag": "0034_aspiring_secret_warriors",
"breakpoints": true
} }
] ]
} }

View File

@@ -195,6 +195,7 @@ export const applicationRouter = createTRPCRouter({
dockerfile: input.dockerfile, dockerfile: input.dockerfile,
publishDirectory: input.publishDirectory, publishDirectory: input.publishDirectory,
dockerContextPath: input.dockerContextPath, dockerContextPath: input.dockerContextPath,
dockerBuildStage: input.dockerBuildStage,
}); });
return true; return true;

View File

@@ -156,6 +156,7 @@ export const applications = pgTable("application", {
), ),
dockerfile: text("dockerfile"), dockerfile: text("dockerfile"),
dockerContextPath: text("dockerContextPath"), dockerContextPath: text("dockerContextPath"),
dockerBuildStage: text("dockerBuildStage"),
// Drop // Drop
dropBuildPath: text("dropBuildPath"), dropBuildPath: text("dropBuildPath"),
// Docker swarm json // Docker swarm json
@@ -393,6 +394,7 @@ export const apiSaveBuildType = createSchema
buildType: true, buildType: true,
dockerfile: true, dockerfile: true,
dockerContextPath: true, dockerContextPath: true,
dockerBuildStage: true,
}) })
.required() .required()
.merge(createSchema.pick({ publishDirectory: true })); .merge(createSchema.pick({ publishDirectory: true }));

View File

@@ -12,7 +12,8 @@ export const buildCustomDocker = async (
application: ApplicationNested, application: ApplicationNested,
writeStream: WriteStream, writeStream: WriteStream,
) => { ) => {
const { appName, env, publishDirectory, buildArgs } = application; const { appName, env, publishDirectory, buildArgs, dockerBuildStage } =
application;
const dockerFilePath = getBuildAppDirectory(application); const dockerFilePath = getBuildAppDirectory(application);
try { try {
const image = `${appName}`; const image = `${appName}`;
@@ -25,6 +26,10 @@ export const buildCustomDocker = async (
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."]; const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
if (dockerBuildStage) {
commandArgs.push("--target", dockerBuildStage);
}
for (const arg of args) { for (const arg of args) {
commandArgs.push("--build-arg", arg); commandArgs.push("--build-arg", arg);
} }