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

[POR-1877] [POR-1865] fix autodetection in v2, disable changing branch for existing apps (#3746)

Feroze Mohideen 2 лет назад
Родитель
Сommit
fe81bfad28

+ 11 - 11
dashboard/src/components/porter/Error.tsx

@@ -11,7 +11,7 @@ type Props = {
   errorModalContents?: React.ReactNode;
 };
 
-const Error: React.FC<Props> = ({
+export const Error: React.FC<Props> = ({
   message,
   ctaText,
   ctaOnClick,
@@ -24,16 +24,16 @@ const Error: React.FC<Props> = ({
       <StyledError>
         <i className="material-icons">error_outline</i>
         <Block>
-        <Bold>Error:</Bold>
-        <Text>{message}</Text>
-        {ctaText && (errorModalContents != null || ctaOnClick != null) && (
-          <Cta onClick={() => {
-            errorModalContents ? setErrorModalOpen(true) : ctaOnClick();
-          }}>
-            <Underline>{ctaText}</Underline>
-            <i className="material-icons">open_in_new</i>
-          </Cta>
-        )}
+          <Bold>Error:</Bold>
+          <Text>{message}</Text>
+          {ctaText && (errorModalContents != null || ctaOnClick != null) && (
+            <Cta onClick={() => {
+              errorModalContents ? setErrorModalOpen(true) : ctaOnClick();
+            }}>
+              <Underline>{ctaText}</Underline>
+              <i className="material-icons">open_in_new</i>
+            </Cta>
+          )}
         </Block>
       </StyledError>
       {errorModalOpen &&

+ 32 - 31
dashboard/src/main/home/app-dashboard/app-view/AppDataContainer.tsx

@@ -36,7 +36,7 @@ import ConfirmRedeployModal from "./ConfirmRedeployModal";
 import ImageSettingsTab from "./tabs/ImageSettingsTab";
 import { useAppAnalytics } from "lib/hooks/useAppAnalytics";
 import { useClusterResourceLimits } from "lib/hooks/useClusterResourceLimits";
-import Error from "components/porter/Error";
+import { Error as ErrorComponent } from "components/porter/Error";
 
 // commented out tabs are not yet implemented
 // will be included as support is available based on data from app revisions rather than helm releases
@@ -305,9 +305,9 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
         errorStackTrace: stack,
       });
 
-      if (err.response?.data?.message) {
+      if ((err as any).response?.data?.message) {
         setError("app", {
-          message: `App update failed: ${err.response.data.message}`,
+          message: `App update failed: ${(err as any).response.data.message}`,
         });
       }
     }
@@ -316,8 +316,8 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
   const cancelRedeploy = useCallback(() => {
     const resetProto = previewRevision
       ? PorterApp.fromJsonString(atob(previewRevision.b64_app_proto), {
-          ignoreUnknownFields: true,
-        })
+        ignoreUnknownFields: true,
+      })
       : latestProto;
 
     // we don't store versions of build settings because they are stored in the db, so we just have to use the latest version
@@ -325,12 +325,12 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
     const resetSource =
       porterAppRecord.image_repo_uri && resetProto.image
         ? {
-            type: "docker-registry" as const,
-            image: {
-              repository: resetProto.image.repository,
-              tag: resetProto.image.tag,
-            },
-          }
+          type: "docker-registry" as const,
+          image: {
+            repository: resetProto.image.repository,
+            tag: resetProto.image.tag,
+          },
+        }
         : latestSource;
 
     reset({
@@ -361,10 +361,11 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
     }
 
     if (Object.keys(errors).length > 0) {
+      console.log(errors);
       return errors.app?.message ? (
-        <Error message={errors.app.message} />
+        <ErrorComponent message={errors.app.message} />
       ) : (
-        <Error message="App update failed. If the error persists, please contact support." />
+        <ErrorComponent message="App update failed. If the error persists, please contact support." />
       );
     }
 
@@ -378,8 +379,8 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
   useEffect(() => {
     const newProto = previewRevision
       ? PorterApp.fromJsonString(atob(previewRevision.b64_app_proto), {
-          ignoreUnknownFields: true,
-        })
+        ignoreUnknownFields: true,
+      })
       : latestProto;
 
     // we don't store versions of build settings because they are stored in the db, so we just have to use the latest version
@@ -387,12 +388,12 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
     const newSource =
       porterAppRecord.image_repo_uri && newProto.image
         ? {
-            type: "docker-registry" as const,
-            image: {
-              repository: newProto.image.repository,
-              tag: newProto.image.tag,
-            },
-          }
+          type: "docker-registry" as const,
+          image: {
+            repository: newProto.image.repository,
+            tag: newProto.image.tag,
+          },
+        }
         : latestSource;
 
     reset({
@@ -471,17 +472,17 @@ const AppDataContainer: React.FC<AppDataContainerProps> = ({ tabParam }) => {
             { label: "Environment", value: "environment" },
             ...(latestProto.build
               ? [
-                  {
-                    label: "Build Settings",
-                    value: "build-settings",
-                  },
-                ]
+                {
+                  label: "Build Settings",
+                  value: "build-settings",
+                },
+              ]
               : [
-                  {
-                    label: "Image Settings",
-                    value: "image-settings",
-                  },
-                ]),
+                {
+                  label: "Image Settings",
+                  value: "image-settings",
+                },
+              ]),
             { label: "Settings", value: "settings" },
           ]}
           currentTab={currentTab}

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

@@ -13,9 +13,10 @@ import { z } from "zod";
 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 BuildpackSettings, { DEFAULT_BUILDERS } from "../validate-apply/build-settings/buildpacks/BuildpackSettings";
 import { match } from "ts-pattern";
 import { BuildOptions } from "lib/porter-apps/build";
+import Loading from "components/Loading";
 
 type Props = {
   projectId: number;
@@ -32,7 +33,6 @@ const branchContentsSchema = z
   .array();
 
 type BranchContents = z.infer<typeof branchContentsSchema>;
-type BuildView = "docker" | "pack";
 
 const RepoSettings: React.FC<Props> = ({
   projectId,
@@ -50,8 +50,8 @@ const RepoSettings: React.FC<Props> = ({
     source.git_branch,
   ]);
 
-  const { data: branchContents } = useQuery<BranchContents>(
-    ["getBranchContents", projectId, source.git_branch, source.git_repo_name],
+  const { data: branchContents, isLoading } = useQuery<BranchContents>(
+    ["getBranchContents", projectId, source.git_branch, source.git_repo_name, appExists],
     async () => {
       const res = await api.getBranchContents(
         "<token>",
@@ -69,23 +69,26 @@ const RepoSettings: React.FC<Props> = ({
       return branchContentsSchema.parse(res.data);
     },
     {
-      enabled: repoIsSet && branchIsSet,
+      enabled: repoIsSet && branchIsSet && !appExists,
     }
   );
 
   useEffect(() => {
-    if (!branchContents || appExists) {
+    if (!branchContents) {
       return;
     }
 
-    const hasDockerfile = branchContents.some((item) =>
-      item.path.includes("Dockerfile")
+    const item = branchContents.find((item) =>
+      item.path.includes("Dockerfile") && item.type === "file"
     );
-    setValue("app.build.method", hasDockerfile ? "docker" : "pack");
-    if (!hasDockerfile) {
+    if (item) {
+      setValue("app.build.dockerfile", item.path.startsWith("./") || item.path.startsWith("/") ? item.path : `./${item.path}`);
+      setValue("app.build.method", "docker");
+    } else {
       setValue("app.build.buildpacks", []);
+      setValue("app.build.method", "pack");
     }
-  }, [branchContents, appExists]);
+  }, [branchContents]);
 
   return (
     <div>
@@ -131,26 +134,28 @@ const RepoSettings: React.FC<Props> = ({
             placeholder=""
           />
           {!appExists && (
-            <BackButton
-              width="135px"
-              onClick={() => {
-                setValue("source", {
-                  type: "github",
-                  git_repo_name: "",
-                  git_branch: "",
-                  git_repo_id: 0,
-                  porter_yaml_path: "./porter.yaml",
-                });
+            <>
+              <BackButton
+                width="135px"
+                onClick={() => {
+                  setValue("source", {
+                    type: "github",
+                    git_repo_name: "",
+                    git_branch: "",
+                    git_repo_id: 0,
+                    porter_yaml_path: "./porter.yaml",
+                  });
 
-                setValue("app.build.context", "./");
-              }}
-            >
-              <i className="material-icons">keyboard_backspace</i>
-              Select repo
-            </BackButton>
+                  setValue("app.build.context", "./");
+                }}
+              >
+                <i className="material-icons">keyboard_backspace</i>
+                Select repo
+              </BackButton>
+              <Spacer y={0.5} />
+            </>
           )}
           <Spacer y={0.5} />
-          <Spacer y={0.5} />
           <Text color="helper">Specify your GitHub branch.</Text>
           <Spacer y={0.5} />
           {!source.git_branch && (
@@ -179,22 +184,27 @@ const RepoSettings: React.FC<Props> = ({
                 setValue={() => { }}
                 placeholder=""
               />
-              <BackButton
-                width="145px"
-                onClick={() => {
-                  setValue("source", {
-                    ...source,
-                    git_branch: "",
-                    porter_yaml_path: "./porter.yaml",
-                  });
+              {!appExists &&
+                <>
+                  <BackButton
+                    width="145px"
+                    onClick={() => {
+                      setValue("source", {
+                        ...source,
+                        git_branch: "",
+                        porter_yaml_path: "./porter.yaml",
+                      });
 
-                  setValue("app.build.context", "./");
-                }}
-              >
-                <i className="material-icons">keyboard_backspace</i>
-                Select branch
-              </BackButton>
-              <Spacer y={1} />
+                      setValue("app.build.context", "./");
+                    }}
+                  >
+                    <i className="material-icons">keyboard_backspace</i>
+                    Select branch
+                  </BackButton>
+                  <Spacer y={0.5} />
+                </>
+              }
+              <Spacer y={0.5} />
               <Text color="helper">Specify your application root path.</Text>
               <Spacer y={0.5} />
               <ControlledInput
@@ -204,25 +214,30 @@ const RepoSettings: React.FC<Props> = ({
                 {...register("app.build.context")}
               />
               <Spacer y={1} />
-              <StyledAdvancedBuildSettings
-                showSettings={showSettings}
-                isCurrent={true}
-                onClick={() => {
-                  setShowSettings(!showSettings);
-                }}
-              >
-                {build.method == "docker" ? (
-                  <AdvancedBuildTitle>
-                    <i className="material-icons dropdown">arrow_drop_down</i>
-                    Configure Dockerfile settings
-                  </AdvancedBuildTitle>
-                ) : (
-                  <AdvancedBuildTitle>
-                    <i className="material-icons dropdown">arrow_drop_down</i>
-                    Configure buildpack settings
-                  </AdvancedBuildTitle>
-                )}
-              </StyledAdvancedBuildSettings>
+              {isLoading && !appExists ?
+                <AdvancedBuildTitle>
+                  <Loading />
+                </AdvancedBuildTitle>
+                :
+                <StyledAdvancedBuildSettings
+                  showSettings={showSettings}
+                  onClick={() => {
+                    setShowSettings(!showSettings);
+                  }}
+                >
+                  {build.method == "docker" ? (
+                    <AdvancedBuildTitle>
+                      <i className="material-icons dropdown">arrow_drop_down</i>
+                      Configure Dockerfile settings
+                    </AdvancedBuildTitle>
+                  ) : (
+                    <AdvancedBuildTitle>
+                      <i className="material-icons dropdown">arrow_drop_down</i>
+                      Configure buildpack settings
+                    </AdvancedBuildTitle>
+                  )}
+                </StyledAdvancedBuildSettings>
+              }
 
               <AnimateHeight height={showSettings ? "auto" : 0} duration={1000}>
                 <StyledSourceBox>
@@ -241,9 +256,10 @@ const RepoSettings: React.FC<Props> = ({
                           if (option == "docker") {
                             onChange("docker");
                           } else if (option == "pack") {
-                            // if toggling from docker to pack, initialize buildpacks to empty array
+                            // if toggling from docker to pack, initialize buildpacks to empty array and builder to default
                             onChange("pack");
                             setValue("app.build.buildpacks", []);
+                            setValue("app.build.builder", DEFAULT_BUILDERS[0])
                           }
                         }}
                         label="Build method"
@@ -350,7 +366,7 @@ const StyledAdvancedBuildSettings = styled.div`
     font-size: 20px;
     cursor: pointer;
     border-radius: 20px;
-    transform: ${(props: { showSettings: boolean; isCurrent: boolean }) =>
+    transform: ${(props: { showSettings: boolean }) =>
     props.showSettings ? "" : "rotate(-90deg)"};
   }
 `;

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

@@ -24,7 +24,6 @@ type Props = {
   setAvailableBuildpacks: (buildpacks: Buildpack[]) => void;
   isDetectingBuildpacks: boolean;
   detectBuildpacksError: string;
-  detectAndSetBuildPacks: () => void;
 };
 
 const BuildpackConfigurationModal: React.FC<Props> = ({

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

@@ -29,12 +29,12 @@ type Props = {
   populateBuildValuesOnceAfterDetection?: boolean;
 };
 
-const DEFAULT_BUILDERS = [
+export const DEFAULT_BUILDERS = [
+  "heroku/buildpacks:20",
   "paketobuildpacks/builder-jammy-full:latest",
   "paketobuildpacks/builder:full",
   "heroku/builder:22",
   "heroku/builder-classic:22",
-  "heroku/buildpacks:20",
   "heroku/buildpacks:18",
 ]
 
@@ -55,7 +55,7 @@ const BuildpackSettings: React.FC<Props> = ({
     name: "app.build.buildpacks",
   });
 
-  const { data, status, refetch } = useQuery(
+  const { data, status } = useQuery(
     [
       "detectBuildpacks",
       projectId,
@@ -203,7 +203,6 @@ const BuildpackSettings: React.FC<Props> = ({
           setAvailableBuildpacks={setAvailableBuildpacks}
           isDetectingBuildpacks={status === "loading"}
           detectBuildpacksError={errorMessage}
-          detectAndSetBuildPacks={refetch}
         />
       )}
     </BuildpackConfigurationContainer>