fix: remove feature flag and minor fixes for git branch protection (#28770)

## Description
Fixes minor issues and remove feature flag
`release_git_branch_protection_enabled`

#### PR fixes following issue(s)
Fixes #28771

#### Type of change
- Bug fix (non-breaking change which fixes an issue)

## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
Rudraprasad Das 2023-11-13 13:37:18 +05:30 committed by GitHub
parent 2e90243fc6
commit 2fb73c3260
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 92 additions and 142 deletions

View File

@ -2,37 +2,9 @@ import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlag
import * as _ from "../../../../../support/Objects/ObjectsCore";
let guid: any;
let repoName1: any;
let repoName2: any;
let repoName: any;
describe("Git Branch Protection", function () {
it("Issue 28056 - 1 : Check if protection is not enabled when feature flag is disabled", function () {
_.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
guid = uid;
const wsName = "GitBranchProtect-1" + uid;
const appName = "GitBranchProtect-1" + uid;
_.homePage.CreateNewWorkspace(wsName, true);
_.homePage.CreateAppInWorkspace(wsName, appName);
featureFlagIntercept({
release_git_connect_v2_enabled: true,
release_git_branch_protection_enabled: false,
});
cy.wait(1000);
_.gitSync.CreateNConnectToGitV2();
cy.get("@gitRepoName").then((repName) => {
repoName1 = repName;
_.agHelper.AssertElementExist(_.entityExplorer._entityExplorerWrapper);
_.agHelper.AssertElementExist(_.propPane._propertyPaneSidebar);
_.agHelper.AssertElementEnabledDisabled(
_.gitSync._bottomBarCommit,
0,
false,
);
});
});
});
it("Issue 28056 - 2 : Check if protection is enabled when feature flag is enabled", function () {
_.agHelper.GenerateUUID();
cy.get("@guid").then((uid) => {
@ -43,7 +15,6 @@ describe("Git Branch Protection", function () {
_.homePage.CreateAppInWorkspace(wsName, appName);
featureFlagIntercept({
release_git_connect_v2_enabled: true,
release_git_branch_protection_enabled: true,
});
cy.wait(1000);
@ -54,7 +25,7 @@ describe("Git Branch Protection", function () {
_.gitSync.CreateNConnectToGitV2();
cy.get("@gitRepoName").then((repName) => {
repoName2 = repName;
repoName = repName;
cy.wait("@gitProtectApi").then((res1) => {
expect(res1.response).to.have.property("statusCode", 200);
_.agHelper.AssertElementVisibility(
@ -76,7 +47,6 @@ describe("Git Branch Protection", function () {
});
after(() => {
_.gitSync.DeleteTestGithubRepo(repoName1);
_.gitSync.DeleteTestGithubRepo(repoName2);
_.gitSync.DeleteTestGithubRepo(repoName);
});
});

View File

@ -5,6 +5,7 @@ let ws1Name: string;
let ws2Name: string;
let app1Name: string;
let repoName: any;
let branchName: any;
describe("Git Connect V2", function () {
before(() => {
@ -36,17 +37,21 @@ describe("Git Connect V2", function () {
release_git_connect_v2_enabled: true,
});
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 300, 300);
_.propPane.RenameWidget("Text1", "MyText");
_.propPane.UpdatePropertyFieldValue("Text", "Hello World");
_.gitSync.CommitAndPush();
_.gitSync.CreateGitBranch("test", true);
cy.get("@gitbranchName").then((bName) => {
branchName = bName;
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TEXT, 300, 300);
_.propPane.RenameWidget("Text1", "MyText");
_.propPane.UpdatePropertyFieldValue("Text", "Hello World");
_.gitSync.CommitAndPush();
_.gitSync.ImportAppFromGitV2(ws2Name, repoName);
_.entityExplorer.ExpandCollapseEntity("Widgets");
_.entityExplorer.AssertEntityPresenceInExplorer("MyText");
_.entityExplorer.SelectEntityByName("MyText");
_.propPane.ValidatePropertyFieldValue("Text", "Hello World");
_.gitSync.ImportAppFromGitV2(ws2Name, repoName);
_.gitSync.SwitchGitBranch(branchName);
_.entityExplorer.ExpandCollapseEntity("Widgets");
_.entityExplorer.AssertEntityPresenceInExplorer("MyText");
_.entityExplorer.SelectEntityByName("MyText");
_.propPane.ValidatePropertyFieldValue("Text", "Hello World");
});
});
after(() => {

View File

@ -1034,7 +1034,7 @@ export const ADD_DEPLOY_KEY_STEP_TITLE = () =>
export const HOW_TO_ADD_DEPLOY_KEY = () =>
"How to paste SSH Key in repo and give write access?";
export const CONSENT_ADDED_DEPLOY_KEY = () =>
"I've added deploy key and gave it write access";
"I've added the deploy key and gave it write access";
export const PREVIOUS_STEP = () => "Previous step";
export const GIT_CONNECT_SUCCESS_TITLE = () =>
"Successfully connected to your Git remote repository";
@ -1083,7 +1083,7 @@ export const BRANCH_PROTECTION_CHANGE_RULE = () =>
"You can remove protection on your default branch in Git settings.";
export const BRANCH_TOOLTIP_TITLE = () => "🚫 This is a protected branch";
export const BRANCH_TOOLTIP_MESSAGE = () =>
"You can remove protection on your default branch in Git settings.";
"Please create a new branch or checkout an existing one to edit the app.";
export const GO_TO_SETTINGS = () => "Go to settings";
export const NOW_PROTECT_BRANCH = () =>
"You can now protect your default branch.";

View File

@ -28,8 +28,6 @@ export const FEATURE_FLAG = {
ab_show_templates_instead_of_blank_canvas_enabled:
"ab_show_templates_instead_of_blank_canvas_enabled",
release_app_sidebar_enabled: "release_app_sidebar_enabled",
release_git_branch_protection_enabled:
"release_git_branch_protection_enabled",
license_git_branch_protection_enabled:
"license_git_branch_protection_enabled",
license_widget_rtl_support_enabled: "license_widget_rtl_support_enabled",
@ -66,7 +64,6 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = {
release_anvil_enabled: false,
ab_show_templates_instead_of_blank_canvas_enabled: false,
release_app_sidebar_enabled: false,
release_git_branch_protection_enabled: false,
license_git_branch_protection_enabled: false,
license_widget_rtl_support_enabled: false,
ab_onboarding_flow_start_with_data_dev_only_enabled: false,

View File

@ -185,6 +185,9 @@ export type EventName =
| "GS_GENERATE_KEY_BUTTON_CLICK"
| "GS_CONNECT_BUTTON_ON_GIT_SYNC_MODAL_CLICK"
| "GS_START_USING_GIT"
| "GS_DEFAULT_BRANCH_UPDATE"
| "GS_PROTECTED_BRANCHES_UPDATE"
| "GS_OPEN_GIT_SETTINGS"
| "GIT_DISCARD_WARNING"
| "GIT_DISCARD_CANCEL"
| "GIT_DISCARD"

View File

@ -27,6 +27,10 @@ export const PROVISIONING_SETUP_DOC =
"http://docs.appsmith.com/advanced-concepts/user-provisioning-group-sync";
export const DISCORD_URL = "https://discord.gg/rBTTVJp";
export const ENTERPRISE_PRICING_PAGE = "https://www.appsmith.com/enterprise";
export const DOCS_BRANCH_PROTECTION_URL =
"https://docs.appsmith.com/advanced-concepts/version-control-with-git/working-with-branches#branch-protection";
export const DOCS_DEFAULT_BRANCH_URL =
"https://docs.appsmith.com/advanced-concepts/version-control-with-git/working-with-branches#default-branch";
export const PRICING_PAGE_URL = (
URL: string,

View File

@ -130,18 +130,11 @@ function QuickActionButton({
);
}
const getPullBtnStatus = (
gitStatus: any,
pullFailed: boolean,
isProtected: boolean,
) => {
const getPullBtnStatus = (gitStatus: any, pullFailed: boolean) => {
const { behindCount, isClean } = gitStatus || {};
let message = createMessage(NO_COMMITS_TO_PULL);
let disabled = behindCount === 0;
if (isProtected) {
disabled = false;
message = createMessage(PULL_CHANGES);
} else if (!isClean) {
if (!isClean) {
disabled = true;
message = createMessage(CANNOT_PULL_WITH_LOCAL_UNCOMMITTED_CHANGES);
} else if (pullFailed) {
@ -322,7 +315,7 @@ export default function QuickGitActions() {
const isProtectedMode = useSelector(protectedModeSelector);
const { disabled: pullDisabled, message: pullTooltipMessage } =
getPullBtnStatus(gitStatus, !!pullFailed, isProtectedMode);
getPullBtnStatus(gitStatus, !!pullFailed);
const isPullInProgress = useSelector(getPullInProgress);
const isFetchingGitStatus = useSelector(getIsFetchingGitStatus);

View File

@ -8,7 +8,6 @@ import {
BRANCH_PROTECTION_RULE_1,
BRANCH_PROTECTION_RULE_2,
BRANCH_PROTECTION_RULE_3,
GIT_CONNECT_SUCCESS_MESSAGE,
GIT_CONNECT_SUCCESS_TITLE,
OPEN_GIT_SETTINGS,
START_USING_GIT,
@ -21,10 +20,6 @@ import { useDispatch, useSelector } from "react-redux";
import styled from "styled-components";
import { getCurrentAppGitMetaData } from "@appsmith/selectors/applicationSelectors";
import AnalyticsUtil from "utils/AnalyticsUtil";
import {
getDefaultGitBranchName,
getIsGitProtectedFeatureEnabled,
} from "selectors/gitSyncSelectors";
const Container = styled.div``;
@ -77,10 +72,6 @@ const features = [
function ConnectionSuccess() {
const gitMetadata = useSelector(getCurrentAppGitMetaData);
const defaultBranchName = useSelector(getDefaultGitBranchName);
const isGitProtectedFeatureEnabled = useSelector(
getIsGitProtectedFeatureEnabled,
);
const dispatch = useDispatch();
useEffect(() => {
@ -105,24 +96,20 @@ function ConnectionSuccess() {
tab: GitSyncModalTab.SETTINGS,
}),
);
AnalyticsUtil.logEvent("GS_START_USING_GIT", {
AnalyticsUtil.logEvent("GS_OPEN_GIT_SETTINGS", {
repoUrl: gitMetadata?.remoteUrl,
});
};
const preBranchProtectionContent = () => {
return (
<Text renderAs="p">{createMessage(GIT_CONNECT_SUCCESS_MESSAGE)}</Text>
);
};
const postBranchProtectionContent = () => {
const branchProtectionContent = () => {
return (
<>
<DefaultBranchMessage renderAs="p">
Right now,{" "}
<BranchTag isClosable={false}>{defaultBranchName}</BranchTag> is set
as the default branch and it is protected.
<BranchTag isClosable={false}>
{gitMetadata?.defaultBranchName}
</BranchTag>{" "}
is set as the default branch and it is protected.
</DefaultBranchMessage>
<ProtectionRulesTitle renderAs="p">
{createMessage(BRANCH_PROTECTION_RULES_AS_FOLLOWS)}
@ -144,19 +131,7 @@ function ConnectionSuccess() {
);
};
const preBranchProtectionActions = () => {
return (
<Button
data-testid="t--start-using-git-button"
onClick={handleStartGit}
size="md"
>
{createMessage(START_USING_GIT)}
</Button>
);
};
const postBranchProtectionActions = () => {
const branchProtectionActions = () => {
return (
<>
<Button
@ -184,16 +159,10 @@ function ConnectionSuccess() {
{createMessage(GIT_CONNECT_SUCCESS_TITLE)}
</TitleText>
</TitleContainer>
{isGitProtectedFeatureEnabled
? postBranchProtectionContent()
: preBranchProtectionContent()}
{branchProtectionContent()}
</Container>
</ModalBody>
<ModalFooter>
{isGitProtectedFeatureEnabled
? postBranchProtectionActions()
: preBranchProtectionActions()}
</ModalFooter>
<ModalFooter>{branchProtectionActions()}</ModalFooter>
</>
);
}

View File

@ -14,6 +14,7 @@ import styled from "styled-components";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { useAppsmithEnterpriseLink } from "./hooks";
import AnalyticsUtil from "utils/AnalyticsUtil";
const Container = styled.div`
padding-top: 16px;
@ -70,6 +71,10 @@ function GitDefaultBranch() {
const handleUpdate = () => {
if (selectedValue) {
AnalyticsUtil.logEvent("GS_DEFAULT_BRANCH_UPDATE", {
old_branch: currentDefaultBranch,
new_branch: selectedValue,
});
dispatch(updateGitDefaultBranch({ branchName: selectedValue }));
}
};

View File

@ -2,12 +2,13 @@ import {
APPSMITH_ENTERPRISE,
BRANCH_PROTECTION,
BRANCH_PROTECTION_DESC,
LEARN_MORE,
UPDATE,
createMessage,
} from "@appsmith/constants/messages";
import { updateGitProtectedBranchesInit } from "actions/gitSyncActions";
import { Button, Link, Option, Select, Text } from "design-system";
import { union, xor } from "lodash";
import { xor } from "lodash";
import React, { useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
@ -21,6 +22,8 @@ import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
import { useAppsmithEnterpriseLink } from "./hooks";
import { REMOTE_BRANCH_PREFIX } from "../../constants";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { DOCS_BRANCH_PROTECTION_URL } from "constants/ThirdPartyConstants";
const Container = styled.div`
padding-top: 16px;
@ -60,25 +63,25 @@ function GitProtectedBranches() {
const defaultBranch = useSelector(getDefaultGitBranchName);
const branchNames = useMemo(() => {
const remoteBranchNames = [];
const localBranchNames = [];
const returnVal: string[] = [];
for (const unfilteredBranch of unfilteredBranches) {
if (unfilteredBranch.branchName === defaultBranch) {
continue;
}
if (unfilteredBranch.branchName.includes(REMOTE_BRANCH_PREFIX)) {
remoteBranchNames.push(
unfilteredBranch.branchName.replace(REMOTE_BRANCH_PREFIX, ""),
returnVal.unshift(unfilteredBranch.branchName);
} else if (unfilteredBranch.branchName.includes(REMOTE_BRANCH_PREFIX)) {
const localBranchName = unfilteredBranch.branchName.replace(
REMOTE_BRANCH_PREFIX,
"",
);
if (!returnVal.includes(localBranchName)) {
returnVal.push(
unfilteredBranch.branchName.replace(REMOTE_BRANCH_PREFIX, ""),
);
}
} else {
localBranchNames.push(unfilteredBranch.branchName);
returnVal.push(unfilteredBranch.branchName);
}
}
const branchNames = union(localBranchNames, remoteBranchNames);
if (defaultBranch) {
branchNames.unshift(defaultBranch);
}
return branchNames;
return returnVal;
}, [unfilteredBranches, defaultBranch]);
const isGitProtectedFeatureLicensed = useFeatureFlag(
@ -86,7 +89,7 @@ function GitProtectedBranches() {
);
const protectedBranches = useSelector(getProtectedBranchesSelector);
const isUpdateLoading = useSelector(getIsUpdateProtectedBranchesLoading);
const [selectedValues, setSelectedValues] = useState<string[]>();
const [selectedValues, setSelectedValues] = useState<string[]>([]);
const enterprisePricingLink = useAppsmithEnterpriseLink(
"git_branch_protection",
@ -103,6 +106,7 @@ function GitProtectedBranches() {
const updateIsDisabled = !areProtectedBranchesDifferent;
const handleUpdate = () => {
sendAnalyticsEvent();
dispatch(
updateGitProtectedBranchesInit({
protectedBranches: selectedValues ?? [],
@ -110,6 +114,25 @@ function GitProtectedBranches() {
);
};
const sendAnalyticsEvent = () => {
const eventData = {
branches_added: [] as string[],
branches_removed: [] as string[],
protected_branches: selectedValues,
};
for (const val of selectedValues) {
if (!protectedBranches.includes(val)) {
eventData.branches_added.push(val);
}
}
for (const val of protectedBranches) {
if (!selectedValues.includes(val)) {
eventData.branches_removed.push(val);
}
}
AnalyticsUtil.logEvent("GS_PROTECTED_BRANCHES_UPDATE", eventData);
};
return (
<Container>
<HeadContainer>
@ -117,7 +140,10 @@ function GitProtectedBranches() {
{createMessage(BRANCH_PROTECTION)}
</SectionTitle>
<SectionDesc kind="body-m" renderAs="p">
{createMessage(BRANCH_PROTECTION_DESC)}
{createMessage(BRANCH_PROTECTION_DESC)}{" "}
<StyledLink target="_blank" to={DOCS_BRANCH_PROTECTION_URL}>
{createMessage(LEARN_MORE)}
</StyledLink>
</SectionDesc>
{!isGitProtectedFeatureLicensed && (
<SectionDesc kind="body-m" renderAs="p">

View File

@ -5,8 +5,6 @@ import styled from "styled-components";
import { Divider, ModalBody } from "design-system";
import GitDefaultBranch from "./GitDefaultBranch";
import GitProtectedBranches from "./GitProtectedBranches";
import { useSelector } from "react-redux";
import { getIsGitProtectedFeatureEnabled } from "selectors/gitSyncSelectors";
import { useIsGitAdmin } from "../../hooks/useIsGitAdmin";
const Container = styled.div`
@ -21,16 +19,13 @@ const StyledDivider = styled(Divider)`
`;
function GitSettings() {
const isGitProtectedFeatureEnabled = useSelector(
getIsGitProtectedFeatureEnabled,
);
const isGitAdmin = useIsGitAdmin();
return (
<ModalBody>
<Container>
<GitUserSettings />
{isGitProtectedFeatureEnabled && isGitAdmin ? (
{isGitAdmin ? (
<>
<StyledDivider />
<GitDefaultBranch />

View File

@ -98,7 +98,7 @@ import { addBranchParam, GIT_BRANCH_QUERY_KEY } from "constants/routes";
import {
getCurrentGitBranch,
getDisconnectingGitApplication,
getIsGitProtectedFeatureEnabled,
getIsGitConnectV2Enabled,
getIsGitStatusLiteEnabled,
} from "selectors/gitSyncSelectors";
import { initEditor } from "actions/initActions";
@ -221,6 +221,9 @@ function* connectToGitSaga(action: ConnectToGitReduxAction) {
const applicationId: string = yield select(getCurrentApplicationId);
const currentPageId: string = yield select(getCurrentPageId);
response = yield GitSyncAPI.connect(action.payload, applicationId);
const isGitConnectV2Enabled: boolean = yield select(
getIsGitConnectV2Enabled,
);
const isValidResponse: boolean = yield validateResponse(
response,
@ -233,10 +236,7 @@ function* connectToGitSaga(action: ConnectToGitReduxAction) {
yield put(connectToGitSuccess(response?.data));
const defaultBranch = response?.data?.gitApplicationMetadata?.branchName;
const isGitProtectedFeatureEnabled: boolean = yield select(
getIsGitProtectedFeatureEnabled,
);
if (isGitProtectedFeatureEnabled) {
if (isGitConnectV2Enabled) {
yield put(
updateGitProtectedBranchesInit({
protectedBranches: defaultBranch ? [defaultBranch] : [],
@ -1069,12 +1069,6 @@ function* discardChanges({
}
function* fetchGitProtectedBranchesSaga() {
const isGitProtectedFeatureEnabled: boolean = yield select(
getIsGitProtectedFeatureEnabled,
);
if (!isGitProtectedFeatureEnabled) {
return;
}
let response: ApiResponse<string[]>;
try {
const appId: string = yield select(getCurrentApplicationId);
@ -1111,12 +1105,6 @@ function* fetchGitProtectedBranchesSaga() {
function* updateGitProtectedBranchesSaga({
payload,
}: ReduxAction<{ protectedBranches: string[] }>) {
const isGitProtectedFeatureEnabled: boolean = yield select(
getIsGitProtectedFeatureEnabled,
);
if (!isGitProtectedFeatureEnabled) {
return;
}
const { protectedBranches } = payload;
const applicationId: string = yield select(getCurrentApplicationId);
let response: ApiResponse<string[]>;

View File

@ -239,8 +239,3 @@ export const getIsUpdateProtectedBranchesLoading = (state: AppState) => {
state.ui.gitSync.protectedBranchesLoading
);
};
export const getIsGitProtectedFeatureEnabled = createSelector(
selectFeatureFlags,
(flags) => !!flags?.release_git_branch_protection_enabled,
);