Просмотр исходного кода

POR-1793 read in default build settings from porter.yaml (#3623)

ianedwards 2 лет назад
Родитель
Сommit
61fb431b2d

+ 3 - 2
dashboard/src/lib/hooks/usePorterYaml.ts

@@ -121,13 +121,14 @@ export const usePorterYaml = ({
           .parseAsync(res.data);
         const proto = PorterApp.fromJsonString(atob(data.b64_app_proto));
 
-        const { services, predeploy } = serviceOverrides({
+        const { services, predeploy, build } = serviceOverrides({
           overrides: proto,
           useDefaults,
         });
 
-        if (services.length || predeploy) {
+        if (services.length || predeploy || build) {
           setDetectedServices({
+            build,
             services,
             predeploy,
           });

+ 18 - 0
dashboard/src/lib/porter-apps/build.ts

@@ -0,0 +1,18 @@
+import { buildpackSchema } from "main/home/app-dashboard/types/buildpack";
+import { z } from "zod";
+
+// buildValidator is used to validate inputs for build setting fields
+export const buildValidator = z.discriminatedUnion("method", [
+  z.object({
+    method: z.literal("pack"),
+    context: z.string().min(1).default("./").catch("./"),
+    buildpacks: z.array(buildpackSchema).default([]),
+    builder: z.string(),
+  }),
+  z.object({
+    method: z.literal("docker"),
+    context: z.string().min(1).default("./").catch("./"),
+    dockerfile: z.string().min(1).default("./Dockerfile").catch("./Dockerfile"),
+  }),
+]);
+export type BuildOptions = z.infer<typeof buildValidator>;

+ 17 - 22
dashboard/src/lib/porter-apps/index.ts

@@ -1,13 +1,9 @@
-import {
-  BUILDPACK_TO_NAME,
-  buildpackSchema,
-} from "main/home/app-dashboard/types/buildpack";
+import { BUILDPACK_TO_NAME } from "main/home/app-dashboard/types/buildpack";
 import { z } from "zod";
 import {
   DetectedServices,
   defaultSerialized,
   deserializeService,
-  isPredeployService,
   serializeService,
   serializedServiceFromProto,
   serviceProto,
@@ -16,22 +12,7 @@ import {
 import { Build, PorterApp, Service } from "@porter-dev/api-contracts";
 import { match } from "ts-pattern";
 import { KeyValueType } from "main/home/cluster-dashboard/env-groups/EnvGroupArray";
-
-// buildValidator is used to validate inputs for build setting fields
-export const buildValidator = z.discriminatedUnion("method", [
-  z.object({
-    method: z.literal("pack"),
-    context: z.string().default("./"),
-    buildpacks: z.array(buildpackSchema).default([]),
-    builder: z.string(),
-  }),
-  z.object({
-    method: z.literal("docker"),
-    context: z.string().default("./"),
-    dockerfile: z.string().default("./Dockerfile"),
-  }),
-]);
-export type BuildOptions = z.infer<typeof buildValidator>;
+import { BuildOptions, buildValidator } from "./build";
 
 // sourceValidator is used to validate inputs for source setting fields
 export const sourceValidator = z.discriminatedUnion("type", [
@@ -117,7 +98,10 @@ export function serviceOverrides({
     .map((svc) => {
       if (useDefaults) {
         return deserializeService({
-          service: defaultSerialized({ name: svc.name, type: svc.config.type }),
+          service: defaultSerialized({
+            name: svc.name,
+            type: svc.config.type,
+          }),
           override: svc,
           expanded: true,
         });
@@ -126,6 +110,15 @@ export function serviceOverrides({
       return deserializeService({ service: svc });
     });
 
+  const validatedBuild = buildValidator
+    .default({
+      method: "pack",
+      context: "./",
+      buildpacks: [],
+      builder: "",
+    })
+    .parse(overrides.build);
+
   if (!overrides.predeploy) {
     return {
       services,
@@ -134,6 +127,7 @@ export function serviceOverrides({
 
   if (useDefaults) {
     return {
+      build: validatedBuild,
       services,
       predeploy: deserializeService({
         service: defaultSerialized({
@@ -151,6 +145,7 @@ export function serviceOverrides({
   }
 
   return {
+    build: validatedBuild,
     services,
     predeploy: deserializeService({
       service: serializedServiceFromProto({

+ 2 - 0
dashboard/src/lib/porter-apps/services.ts

@@ -16,10 +16,12 @@ import {
   ServiceField,
 } from "./values";
 import { Service, ServiceType } from "@porter-dev/api-contracts";
+import { BuildOptions } from "./build";
 
 export type DetectedServices = {
   services: ClientService[];
   predeploy?: ClientService;
+  build?: BuildOptions;
 };
 type ClientServiceType = "web" | "worker" | "job" | "predeploy";
 

+ 6 - 2
dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx

@@ -185,7 +185,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
     loading: isLoadingPorterYaml,
   } = usePorterYaml({
     source: source?.type === "github" ? source : null,
-    appName: name.value,
+    appName: "", // only want to know if porter.yaml has name set, otherwise use name from input
   });
   const deploymentTarget = useDefaultDeploymentTarget();
   const { updateAppStep } = useAppAnalytics(name.value);
@@ -426,9 +426,13 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
 
   useEffect(() => {
     if (servicesFromYaml && !detectedServices.detected) {
-      const { services, predeploy } = servicesFromYaml;
+      const { services, predeploy, build: detectedBuild } = servicesFromYaml;
       setValue("app.services", services);
       setValue("app.predeploy", [predeploy].filter(valueExists));
+
+      if (detectedBuild) {
+        setValue("app.build", detectedBuild);
+      }
       setDetectedServices({
         detected: true,
         count: services.length,

+ 6 - 6
dashboard/src/main/home/app-dashboard/create-app/RepoSettings.tsx

@@ -10,15 +10,12 @@ import { ControlledInput } from "components/porter/ControlledInput";
 import Select from "components/porter/Select";
 import AnimateHeight from "react-animate-height";
 import { z } from "zod";
-import {
-  BuildOptions,
-  PorterAppFormData,
-  SourceOptions,
-} from "lib/porter-apps";
+import { PorterAppFormData, SourceOptions } from "lib/porter-apps";
 import RepositorySelector from "../build-settings/RepositorySelector";
 import BranchSelector from "../build-settings/BranchSelector";
 import BuildpackSettings from "../validate-apply/build-settings/buildpacks/BuildpackSettings";
 import { match } from "ts-pattern";
+import { BuildOptions } from "lib/porter-apps/build";
 
 type Props = {
   projectId: number;
@@ -85,6 +82,9 @@ const RepoSettings: React.FC<Props> = ({
       item.path.includes("Dockerfile")
     );
     setValue("app.build.method", hasDockerfile ? "docker" : "pack");
+    if (!hasDockerfile) {
+      setValue("app.build.buildpacks", []);
+    }
   }, [branchContents]);
 
   return (
@@ -235,7 +235,7 @@ const RepoSettings: React.FC<Props> = ({
                     ]}
                     setValue={(option: string) => {
                       if (option == "docker") {
-                        setValue("app.build.method", "docker");4
+                        setValue("app.build.method", "docker");
                       } else if (option == "pack") {
                         // if toggling from docker to pack, initialize buildpacks to empty array
                         setValue("app.build.method", "pack");

+ 2 - 1
dashboard/src/main/home/app-dashboard/validate-apply/build-settings/buildpacks/BuildpackConfigurationModal.tsx

@@ -11,7 +11,8 @@ import Select from "components/porter/Select";
 import stars from "assets/stars-white.svg";
 import { Buildpack } from "main/home/app-dashboard/types/buildpack";
 import { Controller, useFieldArray, useFormContext } from "react-hook-form";
-import { BuildOptions, PorterAppFormData } from "lib/porter-apps";
+import { PorterAppFormData } from "lib/porter-apps";
+import { BuildOptions } from "lib/porter-apps/build";
 
 type Props = {
   build: BuildOptions & {

+ 2 - 1
dashboard/src/main/home/app-dashboard/validate-apply/build-settings/buildpacks/BuildpackList.tsx

@@ -7,7 +7,8 @@ import Error from "components/porter/Error";
 import { Droppable, DragDropContext } from "react-beautiful-dnd";
 import { Buildpack } from "main/home/app-dashboard/types/buildpack";
 import { useFieldArray, useFormContext } from "react-hook-form";
-import { BuildOptions, PorterAppFormData } from "lib/porter-apps";
+import { PorterAppFormData } from "lib/porter-apps";
+import { BuildOptions } from "lib/porter-apps/build";
 
 interface Props {
   build: BuildOptions & {

+ 2 - 5
dashboard/src/main/home/app-dashboard/validate-apply/build-settings/buildpacks/BuildpackSettings.tsx

@@ -18,11 +18,8 @@ import Button from "components/porter/Button";
 import BuildpackList from "./BuildpackList";
 import BuildpackConfigurationModal from "./BuildpackConfigurationModal";
 import { useFieldArray, useFormContext } from "react-hook-form";
-import {
-  BuildOptions,
-  PorterAppFormData,
-  SourceOptions,
-} from "lib/porter-apps";
+import { PorterAppFormData, SourceOptions } from "lib/porter-apps";
+import { BuildOptions } from "lib/porter-apps/build";
 
 type Props = {
   projectId: number;

+ 0 - 3
internal/porter_app/v1/yaml.go

@@ -19,9 +19,6 @@ func AppProtoFromYaml(ctx context.Context, porterYamlBytes []byte, appName strin
 	ctx, span := telemetry.NewSpan(ctx, "v1-app-proto-from-yaml")
 	defer span.End()
 
-	if appName == "" {
-		return nil, nil, telemetry.Error(ctx, span, nil, "app name is empty")
-	}
 	telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "app-name", Value: appName})
 
 	if porterYamlBytes == nil {

+ 0 - 3
internal/porter_app/v2/yaml.go

@@ -39,9 +39,6 @@ func AppProtoFromYaml(ctx context.Context, porterYamlBytes []byte, appName strin
 		Name: porterYaml.Name,
 	}
 
-	if appProto.Name == "" {
-		return nil, nil, telemetry.Error(ctx, span, nil, "app name is empty")
-	}
 
 	if porterYaml.Build != nil {
 		appProto.Build = &porterv1.Build{