Selaa lähdekoodia

Fix bug where buildpacks aren't detected when switching from docker (#3210)

Feroze Mohideen 2 vuotta sitten
vanhempi
sitoutus
0792818c31

+ 1 - 1
dashboard/src/main/home/app-dashboard/build-settings/AdvancedBuildSettings.tsx

@@ -57,7 +57,7 @@ const AdvancedBuildSettings: React.FC<AdvancedBuildSettingsProps> = ({
               { value: "docker", label: "Docker" },
               { value: "buildpacks", label: "Buildpacks" },
             ]}
-            setValue={(option) => setBuildView(option)}
+            setValue={setBuildView}
             label="Build method"
           />
           {buildView === "docker"

+ 145 - 0
dashboard/src/main/home/app-dashboard/build-settings/buildpacks/BuildpackConfigurationModal.tsx

@@ -0,0 +1,145 @@
+import Spacer from 'components/porter/Spacer';
+import Text from 'components/porter/Text';
+import React from 'react';
+import BuildpackList from './BuildpackList';
+import AddCustomBuildpackComponent from './AddCustomBuildpackComponent';
+import Icon from 'components/porter/Icon';
+import Button from 'components/porter/Button';
+import Modal from 'components/porter/Modal';
+import styled from 'styled-components';
+import Select from 'components/porter/Select';
+import stars from "assets/stars-white.svg";
+import { Buildpack } from '../../types/buildpack';
+import { PorterApp } from '../../types/porterApp';
+
+interface Props {
+    closeModal: () => void;
+    selectedStack: string;
+    sortedStackOptions: { value: string; label: string }[];
+    setStackValue: (value: string) => void;
+    selectedBuildpacks: Buildpack[];
+    setSelectedBuildpacks: (buildpacks: Buildpack[]) => void;
+    availableBuildpacks: Buildpack[];
+    setAvailableBuildpacks: (buildpacks: Buildpack[]) => void;
+    porterApp: PorterApp;
+    updatePorterApp: (attrs: Partial<PorterApp>) => void;
+    isDetectingBuildpacks: boolean;
+    detectBuildpacksError: string;
+    handleAddCustomBuildpack: (buildpack: Buildpack) => void;
+    detectAndSetBuildPacks: (detect: boolean) => void;
+}
+const BuildpackConfigurationModal: React.FC<Props> = ({
+    closeModal,
+    selectedStack,
+    sortedStackOptions,
+    setStackValue,
+    selectedBuildpacks,
+    setSelectedBuildpacks,
+    availableBuildpacks,
+    setAvailableBuildpacks,
+    porterApp,
+    updatePorterApp,
+    isDetectingBuildpacks,
+    detectBuildpacksError,
+    handleAddCustomBuildpack,
+    detectAndSetBuildPacks,
+}) => {
+    return (
+        <Modal closeModal={closeModal}>
+            <Text size={16}>Buildpack Configuration</Text>
+            <Spacer y={1} />
+            <Scrollable>
+                <Text>Builder:</Text>
+                {selectedStack === "" &&
+                    <>
+                        <Spacer y={0.5} />
+                        <Text color="helper">
+                            No builder detected. Click 'Detect buildpacks' below to scan your repository for available builders and buildpacks.
+                        </Text>
+                    </>
+                }
+                {selectedStack !== "" &&
+                    <>
+                        <Spacer y={0.5} />
+                        <Select
+                            value={selectedStack}
+                            width="300px"
+                            options={sortedStackOptions}
+                            setValue={setStackValue}
+                        />
+                    </>
+                }
+                <BuildpackList
+                    selectedBuildpacks={selectedBuildpacks}
+                    setSelectedBuildpacks={setSelectedBuildpacks}
+                    availableBuildpacks={availableBuildpacks}
+                    setAvailableBuildpacks={setAvailableBuildpacks}
+                    porterApp={porterApp}
+                    updatePorterApp={updatePorterApp}
+                    showAvailableBuildpacks={true}
+                    isDetectingBuildpacks={isDetectingBuildpacks}
+                    detectBuildpacksError={detectBuildpacksError}
+                    droppableId={"modal"}
+                />
+                <Spacer y={0.5} />
+                <Text>
+                    Custom buildpacks
+                </Text>
+                <Spacer y={0.5} />
+                <Text color="helper">
+                    You may also add buildpacks by directly providing their GitHub links
+                    or links to ZIP files that contain the buildpack source code.
+                </Text>
+                <Spacer y={1} />
+                <AddCustomBuildpackComponent onAdd={handleAddCustomBuildpack} />
+                <Spacer y={2} />
+            </Scrollable>
+            <Footer>
+                <Shade />
+                <FooterButtons>
+                    <Button onClick={() => detectAndSetBuildPacks(true)}>
+                        <Icon src={stars} height="15px" />
+                        <Spacer inline x={0.5} />
+                        Detect buildpacks
+                    </Button>
+                    <Button onClick={closeModal} width={"75px"}>Close</Button>
+                </FooterButtons>
+            </Footer>
+        </Modal>
+    );
+}
+export default BuildpackConfigurationModal;
+
+const Scrollable = styled.div`
+  overflow-y: auto;
+  padding: 0 25px;
+  width: calc(100% + 50px);
+  margin-left: -25px;
+  max-height: calc(100vh - 300px);
+`;
+
+const FooterButtons = styled.div`
+  display: flex;
+  justify-content: space-between;
+`;
+
+const Footer = styled.div`
+  position: relative;
+  width: calc(100% + 50px);
+  margin-left: -25px;
+  padding: 0 25px;
+  border-bottom-left-radius: 10px;
+  border-bottom-right-radius: 10px;
+  background: ${({ theme }) => theme.fg};
+  margin-bottom: -30px;
+  padding-bottom: 30px;
+`;
+
+const Shade = styled.div`
+  position: absolute;
+  top: -50px;
+  left: 0;
+  height: 50px;
+  width: 100%;
+  background: linear-gradient(to bottom, #00000000, ${({ theme }) => theme.fg});
+`;

+ 26 - 29
dashboard/src/main/home/app-dashboard/build-settings/buildpacks/BuildpackList.tsx

@@ -79,33 +79,20 @@ const BuildpackList: React.FC<Props> = ({
         }
 
         if (availableBuildpacks.length > 0) {
-            return (
-                <>
-                    <Spacer y={0.5} />
-                    <Text>Available buildpacks:</Text>
-                    <Spacer y={0.5} />
-                    {availableBuildpacks.map((buildpack, index) => {
-                        return (
-                            <BuildpackCard
-                                buildpack={buildpack}
-                                action={"add"}
-                                onClickFn={handleAddBuildpack}
-                                index={index}
-                                draggable={false}
-                            />
-                        )
-                    })
-                    }
-                </>
-            )
+            return availableBuildpacks.map((buildpack, index) => {
+                return (
+                    <BuildpackCard
+                        buildpack={buildpack}
+                        action={"add"}
+                        onClickFn={handleAddBuildpack}
+                        index={index}
+                        draggable={false}
+                    />
+                )
+            })
         }
 
-        return (
-            <>
-                <Spacer y={0.5} />
-                <Text color="helper">No buildpacks detected. Click 'Detect buildpacks' below to scan your repository for available buildpacks.</Text>
-            </>
-        )
+        return <Text color="helper">No available buildpacks detected.</Text>
     }
 
     return (
@@ -117,13 +104,13 @@ const BuildpackList: React.FC<Props> = ({
                     <Spacer y={0.5} />
                 </>
             }
-            <Droppable droppableId={droppableId}>
+            {selectedBuildpacks.length !== 0 && <Droppable droppableId={droppableId}>
                 {provided => (
                     <div
                         {...provided.droppableProps}
                         ref={provided.innerRef}
                     >
-                        {selectedBuildpacks?.map((buildpack, index) => (
+                        {selectedBuildpacks.map((buildpack, index) => (
                             <BuildpackCard
                                 buildpack={buildpack}
                                 action={"remove"}
@@ -136,8 +123,18 @@ const BuildpackList: React.FC<Props> = ({
                         {provided.placeholder}
                     </div>
                 )}
-            </Droppable>
-            {showAvailableBuildpacks && renderAvailableBuildpacks()}
+            </Droppable>}
+            {selectedBuildpacks.length === 0 &&
+                <Text color="helper">No buildpacks selected.</Text>
+            }
+            {showAvailableBuildpacks &&
+                <>
+                    <Spacer y={0.5} />
+                    <Text>Available buildpacks:</Text>
+                    <Spacer y={0.5} />
+                    {renderAvailableBuildpacks()}
+                </>
+            }
         </DragDropContext>
     );
 };

+ 47 - 156
dashboard/src/main/home/app-dashboard/build-settings/buildpacks/BuildpackSettings.tsx

@@ -1,20 +1,13 @@
 import Helper from "components/form-components/Helper";
-import Select from "components/porter/Select";
-import Loading from "components/Loading";
 import React, { useContext, useEffect, useMemo, useState } from "react";
 import api from "shared/api";
 import { Context } from "shared/Context";
 import styled, { keyframes } from "styled-components";
 import Button from "components/porter/Button";
-import Modal from "components/porter/Modal";
 import Spacer from "components/porter/Spacer";
-import Text from "components/porter/Text";
 import Error from "components/porter/Error";
 import { PorterApp } from "../../types/porterApp";
-import AddCustomBuildpackComponent from "./AddCustomBuildpackComponent";
 import BuildpackList from "./BuildpackList";
-import Icon from "components/porter/Icon";
-import stars from "assets/stars-white.svg";
 import {
   BUILDPACK_TO_NAME,
   BuildConfig,
@@ -23,6 +16,7 @@ import {
   DEFAULT_HEROKU_STACK,
   DetectedBuildpack
 } from "../../types/buildpack";
+import BuildpackConfigurationModal from "./BuildpackConfigurationModal";
 
 const BuildpackSettings: React.FC<{
   porterApp: PorterApp;
@@ -35,66 +29,15 @@ const BuildpackSettings: React.FC<{
 }) => {
     const { currentProject } = useContext(Context);
 
-    const [builders, setBuilders] = useState<DetectedBuildpack[]>([]);
     const [selectedStack, setSelectedStack] = useState<string>("");
+    const [stackOptions, setStackOptions] = useState<{ label: string; value: string }[]>([]);
     const [isModalOpen, setIsModalOpen] = useState(false);
     const [isDetectingBuildpacks, setIsDetectingBuildpacks] = useState(false);
     const [error, setError] = useState<string>("");
 
     const [selectedBuildpacks, setSelectedBuildpacks] = useState<Buildpack[]>([]);
     const [availableBuildpacks, setAvailableBuildpacks] = useState<Buildpack[]>([]);
-    const renderModalContent = () => {
-      return (
-        <>
-          <Text size={16}>Buildpack Configuration</Text>
-          <Spacer y={1} />
-          <Scrollable>
-            <Select
-              value={selectedStack}
-              width="300px"
-              options={sortedStackOptions}
-              setValue={(option) => {
-                setSelectedStack(option);
-                updatePorterApp({ builder: option });
-              }}
-              label="Builder and stack"
-            />
-            <Spacer y={0.5} />
-            <BuildpackList
-              selectedBuildpacks={selectedBuildpacks}
-              setSelectedBuildpacks={setSelectedBuildpacks}
-              availableBuildpacks={availableBuildpacks}
-              setAvailableBuildpacks={setAvailableBuildpacks}
-              porterApp={porterApp}
-              updatePorterApp={updatePorterApp}
-              showAvailableBuildpacks={true}
-              isDetectingBuildpacks={isDetectingBuildpacks}
-              detectBuildpacksError={error}
-              droppableId={"modal"}
-            />
-            <Spacer y={0.5} />
-            <Text color="helper">
-              You may also add buildpacks by directly providing their GitHub links
-              or links to ZIP files that contain the buildpack source code.
-            </Text>
-            <Spacer y={1} />
-            <AddCustomBuildpackComponent onAdd={handleAddCustomBuildpack} />
-            <Spacer y={2} />
-          </Scrollable>
-          <Footer>
-            <Shade />
-            <FooterButtons>
-              <Button onClick={() => detectAndSetBuildPacks(true)}>
-                <Icon src={stars} height="15px" />
-                <Spacer inline x={0.5} />
-                Detect buildpacks
-              </Button>
-              <Button onClick={() => setIsModalOpen(false)} width={"75px"}>Save</Button>
-            </FooterButtons>
-          </Footer>
-        </>
-      );
-    };
+
     const detectAndSetBuildPacks = async (detect: boolean) => {
       try {
         if (currentProject == null) {
@@ -103,20 +46,16 @@ const BuildpackSettings: React.FC<{
 
         if (!detect) {
           // in this case, we are not detecting buildpacks, so we just populate based on the DB
-          setBuilders([{
-            name: porterApp.builder.split("/")[0],
-            builders: [porterApp.builder],
-            detected: [],
-            others: [],
-            buildConfig: {} as BuildConfig,
-          }])
-          setSelectedStack(porterApp.builder);
-          setSelectedBuildpacks(porterApp.buildpacks?.map(bp => ({
-            name: BUILDPACK_TO_NAME[bp] ?? bp,
-            buildpack: bp,
-            config: {},
-          })) ?? []);
-          setAvailableBuildpacks([]);
+          if (porterApp.builder != null) {
+            setSelectedStack(porterApp.builder);
+          }
+          if (porterApp.buildpacks != null) {
+            setSelectedBuildpacks(porterApp.buildpacks.map(bp => ({
+              name: BUILDPACK_TO_NAME[bp] ?? bp,
+              buildpack: bp,
+              config: {},
+            })));
+          }
         } else {
           if (isDetectingBuildpacks) {
             return;
@@ -141,7 +80,20 @@ const BuildpackSettings: React.FC<{
           if (builders.length === 0) {
             return;
           }
-          setBuilders(builders);
+          setStackOptions(builders.flatMap((builder) => {
+            return builder.builders.map((stack) => ({
+              label: `${builder.name} - ${stack}`,
+              value: stack.toLowerCase(),
+            }));
+          }).sort((a, b) => {
+            if (a.label < b.label) {
+              return -1;
+            }
+            if (a.label > b.label) {
+              return 1;
+            }
+            return 0;
+          }));
 
           const defaultBuilder = builders.find(
             (builder) => builder.name.toLowerCase() === DEFAULT_BUILDER_NAME
@@ -169,12 +121,7 @@ const BuildpackSettings: React.FC<{
           }
         }
       } catch (err) {
-        if (autoDetectBuildpacks) {
-          updatePorterApp({ buildpacks: [] });
-          setSelectedBuildpacks([]);
-          setAvailableBuildpacks([]);
-          setError(`Unable to detect buildpacks at path: ${porterApp.build_context}. Please make sure your repo, branch, and application root path are all set correctly and attempt to detect again.`);
-        }
+        setError(`Unable to detect buildpacks at path: ${porterApp.build_context}. Please make sure your repo, branch, and application root path are all set correctly and attempt to detect again.`);
       } finally {
         setIsDetectingBuildpacks(false);
       }
@@ -184,30 +131,6 @@ const BuildpackSettings: React.FC<{
       detectAndSetBuildPacks(autoDetectBuildpacks);
     }, [currentProject]);
 
-    const builderOptions = useMemo(() => {
-      if (!Array.isArray(builders)) {
-        return;
-      }
-
-      return builders.map((builder) => ({
-        label: builder.name,
-        value: builder.name.toLowerCase(),
-      }));
-    }, [builders]);
-
-    const stackOptions = useMemo(() => {
-      if (!Array.isArray(builders)) {
-        return;
-      }
-
-      return builders.flatMap((builder) => {
-        return builder.builders.map((stack) => ({
-          label: `${builder.name} - ${stack}`,
-          value: stack.toLowerCase(),
-        }));
-      });
-    }, [builders]);
-
     const handleAddCustomBuildpack = (buildpack: Buildpack) => {
       if (porterApp.buildpacks.find((bp) => bp === buildpack.buildpack) == null) {
         updatePorterApp({ buildpacks: [...porterApp.buildpacks, buildpack.buildpack] });
@@ -215,20 +138,6 @@ const BuildpackSettings: React.FC<{
       }
     };
 
-    if (!stackOptions?.length || !builderOptions?.length) {
-      return <Loading />;
-    }
-
-    const sortedStackOptions = stackOptions.sort((a, b) => {
-      if (a.label < b.label) {
-        return -1;
-      }
-      if (a.label > b.label) {
-        return 1;
-      }
-      return 0;
-    });
-
     return (
       <BuildpackConfigurationContainer>
         {selectedBuildpacks.length > 0 && (
@@ -265,9 +174,25 @@ const BuildpackSettings: React.FC<{
           <I className="material-icons">add</I> Add / detect buildpacks
         </Button>
         {isModalOpen && (
-          <Modal closeModal={() => setIsModalOpen(false)}>
-            {renderModalContent()}
-          </Modal>
+          <BuildpackConfigurationModal
+            closeModal={() => setIsModalOpen(false)}
+            selectedStack={selectedStack}
+            sortedStackOptions={stackOptions}
+            setStackValue={(option) => {
+              setSelectedStack(option);
+              updatePorterApp({ builder: option });
+            }}
+            selectedBuildpacks={selectedBuildpacks}
+            setSelectedBuildpacks={setSelectedBuildpacks}
+            availableBuildpacks={availableBuildpacks}
+            setAvailableBuildpacks={setAvailableBuildpacks}
+            porterApp={porterApp}
+            updatePorterApp={updatePorterApp}
+            isDetectingBuildpacks={isDetectingBuildpacks}
+            detectBuildpacksError={error}
+            handleAddCustomBuildpack={handleAddCustomBuildpack}
+            detectAndSetBuildPacks={detectAndSetBuildPacks}
+          />
         )}
       </BuildpackConfigurationContainer>
     );
@@ -276,32 +201,6 @@ const BuildpackSettings: React.FC<{
 export default BuildpackSettings;
 
 
-const Shade = styled.div`
-  position: absolute;
-  top: -50px;
-  left: 0;
-  height: 50px;
-  width: 100%;
-  background: linear-gradient(to bottom, #00000000, ${({ theme }) => theme.fg});
-`;
-
-const FooterButtons = styled.div`
-  display: flex;
-  justify-content: space-between;
-`;
-
-const Footer = styled.div`
-  position: relative;
-  width: calc(100% + 50px);
-  margin-left: -25px;
-  padding: 0 25px;
-  border-bottom-left-radius: 10px;
-  border-bottom-right-radius: 10px;
-  background: ${({ theme }) => theme.fg};
-  margin-bottom: -30px;
-  padding-bottom: 30px;
-`;
-
 const I = styled.i`
   color: white;
   font-size: 14px;
@@ -311,14 +210,6 @@ const I = styled.i`
   justify-content: center;
 `;
 
-const Scrollable = styled.div`
-  overflow-y: auto;
-  padding: 0 25px;
-  width: calc(100% + 50px);
-  margin-left: -25px;
-  max-height: calc(100vh - 300px);
-`;
-
 const fadeIn = keyframes`
   from {
     opacity: 0;