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

Merge pull request #2155 from porter-dev/nico/por-515-allow-user-to-change-the-branch-of-a

[POR-515] Allow user to change the default branch for an application
abelanger5 3 лет назад
Родитель
Сommit
42846b8e3e

+ 57 - 0
api/server/handlers/release/update_git_action_config.go

@@ -0,0 +1,57 @@
+package release
+
+import (
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+type UpdateGitActionConfigHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewUpdateGitActionConfigHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *UpdateGitActionConfigHandler {
+	return &UpdateGitActionConfigHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *UpdateGitActionConfigHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	release, _ := r.Context().Value(types.ReleaseScope).(*models.Release)
+
+	request := &types.UpdateGitActionConfigRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	actionConfig, err := c.Repo().GitActionConfig().ReadGitActionConfig(release.GitActionConfig.ID)
+
+	if err != nil {
+		if err == gorm.ErrRecordNotFound {
+			w.WriteHeader(http.StatusNotFound)
+			return
+		}
+
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+	}
+
+	actionConfig.GitBranch = request.GitActionConfig.GitBranch
+
+	if err := c.Repo().GitActionConfig().UpdateGitActionConfig(actionConfig); err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+}

+ 31 - 0
api/server/router/release.go

@@ -815,5 +815,36 @@ func getReleaseRoutes(
 		Router:   r,
 	})
 
+	// PATCH /api/projects/{project_id}/clusters/{cluster_id}/namespaces/{namespace}/releases/{name}/{version}/git_action_config -> release.NewUpdateGitActionConfigHandler
+	updateGitActionConfigEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbUpdate,
+			Method: types.HTTPVerbPatch,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: "/releases/{name}/{version}/git_action_config",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+				types.NamespaceScope,
+				types.ReleaseScope,
+			},
+		},
+	)
+
+	updateGitActionConfigHandler := release.NewUpdateGitActionConfigHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: updateGitActionConfigEndpoint,
+		Handler:  updateGitActionConfigHandler,
+		Router:   r,
+	})
+
 	return routes, newPath
 }

+ 10 - 0
api/types/release.go

@@ -193,3 +193,13 @@ type GetReleaseAllPodsResponse []v1.Pod
 type PatchUpdateReleaseTags struct {
 	Tags []string `json:"tags"`
 }
+
+type PartialGitActionConfig struct {
+	// The branch to use for the git repository
+	// required: true
+	GitBranch string `json:"branch" form:"required"`
+}
+
+type UpdateGitActionConfigRequest struct {
+	GitActionConfig *PartialGitActionConfig `json:"git_action_config"`
+}

+ 16 - 5
dashboard/src/components/repo-selector/BranchList.tsx

@@ -12,9 +12,14 @@ import SearchBar from "../SearchBar";
 type Props = {
   actionConfig: ActionConfigType;
   setBranch: (x: string) => void;
+  currentBranch?: string;
 };
 
-const BranchList: React.FC<Props> = ({ setBranch, actionConfig }) => {
+const BranchList: React.FC<Props> = ({
+  setBranch,
+  actionConfig,
+  currentBranch,
+}) => {
   const [loading, setLoading] = useState(true);
   const [error, setError] = useState(false);
   const [branches, setBranches] = useState<string[]>([]);
@@ -108,6 +113,9 @@ const BranchList: React.FC<Props> = ({ setBranch, actionConfig }) => {
         >
           <img src={branch_icon} alt={"branch icon"} />
           {branch}
+          {currentBranch === branch && (
+            <i className="material-icons-outlined">check</i>
+          )}
         </BranchName>
       );
     });
@@ -144,10 +152,6 @@ const BranchName = styled.div`
   background: #ffffff11;
   :hover {
     background: #ffffff22;
-
-    > i {
-      background: #ffffff22;
-    }
   }
 
   > img {
@@ -156,6 +160,13 @@ const BranchName = styled.div`
     margin-left: 12px;
     margin-right: 12px;
   }
+
+  > i {
+    margin-left: auto;
+    margin-right: 15px;
+    font-size: 18px;
+    color: #03b503;
+  }
 `;
 
 const LoadingWrapper = styled.div`

+ 54 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/BuildSettingsTab.tsx

@@ -18,6 +18,9 @@ import yaml from "js-yaml";
 import { AxiosError } from "axios";
 import { AddCustomBuildpackForm } from "components/repo-selector/BuildpackSelection";
 import { DeviconsNameList } from "assets/devicons-name-list";
+import Selector from "components/Selector";
+import BranchList from "components/repo-selector/BranchList";
+import Banner from "components/Banner";
 
 type Buildpack = {
   name: string;
@@ -72,6 +75,42 @@ const BuildSettingsTab: React.FC<Props> = ({ chart, isPreviousVersion }) => {
     "loading" | "successful" | string
   >("");
 
+  const [currentBranch, setCurrentBranch] = useState(
+    () => chart?.git_action_config?.git_branch
+  );
+
+  const saveNewBranch = async (newBranch: string) => {
+    if (!newBranch?.length) {
+      return;
+    }
+
+    if (newBranch === chart?.git_action_config?.git_branch) {
+      return;
+    }
+
+    const newGitActionConfig: FullActionConfigType = {
+      ...chart.git_action_config,
+      git_branch: newBranch,
+    };
+
+    try {
+      api.updateGitActionConfig(
+        "<token>",
+        {
+          git_action_config: newGitActionConfig,
+        },
+        {
+          project_id: currentProject.id,
+          cluster_id: currentCluster.id,
+          release_name: chart.name,
+          namespace: chart.namespace,
+        }
+      );
+    } catch (error) {
+      throw error;
+    }
+  };
+
   const saveBuildConfig = async (config: BuildConfig) => {
     if (config === null) {
       return;
@@ -206,6 +245,7 @@ const BuildSettingsTab: React.FC<Props> = ({ chart, isPreviousVersion }) => {
     setButtonStatus("loading");
     try {
       await saveBuildConfig(buildConfig);
+      await saveNewBranch(currentBranch);
       await saveEnvVariables(envVariables);
       setButtonStatus("successful");
     } catch (error) {
@@ -220,6 +260,7 @@ const BuildSettingsTab: React.FC<Props> = ({ chart, isPreviousVersion }) => {
     setButtonStatus("loading");
     try {
       await saveBuildConfig(buildConfig);
+      await saveNewBranch(currentBranch);
       await saveEnvVariables(envVariables);
       await triggerWorkflow();
       setButtonStatus("successful");
@@ -296,6 +337,19 @@ const BuildSettingsTab: React.FC<Props> = ({ chart, isPreviousVersion }) => {
           }}
         ></KeyValueArray>
 
+        <Heading>Select Default Branch</Heading>
+        <Helper>
+          Change the default branch the deployments will be made from.
+        </Helper>
+        <Banner type="warning">
+          You must also update the deploy branch in your GitHub Action file.
+        </Banner>
+        <BranchList
+          actionConfig={currentActionConfig}
+          setBranch={setCurrentBranch}
+          currentBranch={currentBranch}
+        />
+
         {!chart.git_action_config.dockerfile_path ? (
           <>
             <Heading>Buildpack Settings</Heading>

+ 21 - 2
dashboard/src/shared/api.tsx

@@ -1,9 +1,8 @@
 import { PolicyDocType } from "./auth/types";
 import { PullRequest } from "main/home/cluster-dashboard/preview-environments/types";
-import { release } from "process";
 import { baseApi } from "./baseApi";
 
-import { BuildConfig, FullActionConfigType, StorageType } from "./types";
+import { BuildConfig, FullActionConfigType } from "./types";
 import { CreateStackBody } from "main/home/cluster-dashboard/stacks/types";
 
 /**
@@ -1807,6 +1806,25 @@ const updateBuildConfig = baseApi<
     `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${release_name}/buildconfig`
 );
 
+const updateGitActionConfig = baseApi<
+  {
+    git_action_config: {
+      git_branch: string;
+    };
+  },
+  {
+    project_id: number;
+    cluster_id: number;
+    namespace: string;
+    release_name: string;
+    revision?: 0; // Always update latest
+  }
+>(
+  "PATCH",
+  ({ project_id, cluster_id, namespace, release_name, revision = 0 }) =>
+    `/api/projects/${project_id}/clusters/${cluster_id}/namespaces/${namespace}/releases/${release_name}/${revision}/git_action_config`
+);
+
 const reRunGHWorkflow = baseApi<
   {},
   {
@@ -2182,6 +2200,7 @@ export default {
   upgradePorterAgent,
   deletePRDeployment,
   updateBuildConfig,
+  updateGitActionConfig,
   reRunGHWorkflow,
   triggerPreviewEnvWorkflow,
   getTagsByProjectId,

+ 1 - 0
internal/repository/git_action_config.go

@@ -7,4 +7,5 @@ import "github.com/porter-dev/porter/internal/models"
 type GitActionConfigRepository interface {
 	CreateGitActionConfig(gr *models.GitActionConfig) (*models.GitActionConfig, error)
 	ReadGitActionConfig(id uint) (*models.GitActionConfig, error)
+	UpdateGitActionConfig(gr *models.GitActionConfig) error
 }

+ 4 - 0
internal/repository/gorm/git_action_config.go

@@ -49,3 +49,7 @@ func (repo *GitActionConfigRepository) ReadGitActionConfig(id uint) (*models.Git
 
 	return ga, nil
 }
+
+func (repo *GitActionConfigRepository) UpdateGitActionConfig(ga *models.GitActionConfig) error {
+	return repo.db.Save(ga).Error
+}

+ 14 - 0
internal/repository/test/git_action_config.go

@@ -46,3 +46,17 @@ func (repo *GitActionConfigRepository) ReadGitActionConfig(id uint) (*models.Git
 	index := int(id - 1)
 	return repo.gitActionConfigs[index], nil
 }
+
+func (repo *GitActionConfigRepository) UpdateGitActionConfig(gac *models.GitActionConfig) error {
+	if !repo.canQuery {
+		return errors.New("Cannot write database")
+	}
+
+	if int(gac.ID-1) >= len(repo.gitActionConfigs) || repo.gitActionConfigs[gac.ID-1] == nil {
+		return gorm.ErrRecordNotFound
+	}
+
+	index := int(gac.ID - 1)
+	repo.gitActionConfigs[index] = gac
+	return nil
+}