Skip to content

Commit

Permalink
chore: Send analytics event after branch protection (appsmithorg#29944)
Browse files Browse the repository at this point in the history
## Description
Sends analytics events when branches are protected or un-protected.

#### PR fixes following issue(s)
Fixes appsmithorg#29410
  • Loading branch information
Nayan authored Jan 3, 2024
1 parent a497225 commit 16ddb50
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public enum AnalyticsEvents {
GIT_LIST_LOCAL_BRANCH,
GIT_MERGE_CHECK,
GIT_FETCH,
GIT_ADD_PROTECTED_BRANCH,
GIT_REMOVE_PROTECTED_BRANCH,
AUTHENTICATION_METHOD_CONFIGURATION("Authentication Method Configured"),
INSTANCE_SETTING_UPDATED,
GENERATE_SSH_KEY("generate_SSH_KEY"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

import static com.appsmith.external.constants.AnalyticsEvents.GIT_ADD_PROTECTED_BRANCH;
import static com.appsmith.external.constants.AnalyticsEvents.GIT_REMOVE_PROTECTED_BRANCH;
import static com.appsmith.external.constants.GitConstants.CONFLICTED_SUCCESS_MESSAGE;
import static com.appsmith.external.constants.GitConstants.DEFAULT_COMMIT_MESSAGE;
import static com.appsmith.external.constants.GitConstants.EMPTY_COMMIT_ERROR_MESSAGE;
Expand Down Expand Up @@ -3157,6 +3159,11 @@ private Mono<Application> addAnalyticsForGitOperation(
return addAnalyticsForGitOperation(eventName, application, "", "", isRepoPrivate, false);
}

private Mono<Application> addAnalyticsForGitOperation(
AnalyticsEvents eventName, String branchName, Application application) {
return addAnalyticsForGitOperation(eventName, application, null, null, null, false, null, branchName);
}

private Mono<Application> addAnalyticsForGitOperation(
AnalyticsEvents eventName,
Application application,
Expand Down Expand Up @@ -3185,12 +3192,29 @@ private Mono<Application> addAnalyticsForGitOperation(
Boolean isRepoPrivate,
Boolean isSystemGenerated,
Boolean isMergeable) {

String branchName = application.getGitApplicationMetadata() != null
? application.getGitApplicationMetadata().getBranchName()
: null;
return addAnalyticsForGitOperation(
event, application, errorType, errorMessage, isRepoPrivate, isSystemGenerated, isMergeable, branchName);
}

private Mono<Application> addAnalyticsForGitOperation(
AnalyticsEvents event,
Application application,
String errorType,
String errorMessage,
Boolean isRepoPrivate,
Boolean isSystemGenerated,
Boolean isMergeable,
String branchName) {
GitApplicationMetadata gitData = application.getGitApplicationMetadata();
Map<String, Object> analyticsProps = new HashMap<>();
if (gitData != null) {
analyticsProps.put(FieldName.APPLICATION_ID, gitData.getDefaultApplicationId());
analyticsProps.put("appId", gitData.getDefaultApplicationId());
analyticsProps.put(FieldName.BRANCH_NAME, gitData.getBranchName());
analyticsProps.put(FieldName.BRANCH_NAME, branchName);
analyticsProps.put(FieldName.GIT_HOSTING_PROVIDER, GitUtils.getGitProviderName(gitData.getRemoteUrl()));
analyticsProps.put(FieldName.REPO_URL, gitData.getRemoteUrl());
if (event == AnalyticsEvents.GIT_COMMIT) {
Expand Down Expand Up @@ -3254,11 +3278,17 @@ public Mono<List<String>> updateProtectedBranches(String defaultApplicationId, L

if (branchNames.isEmpty()
|| (branchNames.size() == 1 && branchNames.get(0).equals(defaultBranchName))) {
// keep a copy of old protected branches as it's required to send analytics event later
List<String> oldProtectedBranches = metadata.getBranchProtectionRules() != null
? metadata.getBranchProtectionRules()
: List.of();

// user wants to unprotect all branches or user wants to protect only default branch
metadata.setBranchProtectionRules(branchNames);
return applicationService
.save(rootApplication)
.then(applicationService.updateProtectedBranches(defaultApplicationId, branchNames))
.then(sendBranchProtectionAnalytics(rootApplication, oldProtectedBranches, branchNames))
.thenReturn(branchNames);
} else {
// user want to protect multiple branches, not allowed
Expand Down Expand Up @@ -3331,4 +3361,39 @@ public Mono<Boolean> toggleAutoCommitEnabled(String defaultApplicationId) {
.getAutoCommitConfig()
.getEnabled()));
}

/**
* Sends one or more analytics events when there's a change in protected branches.
* If n number of branches are un-protected and m number of branches are protected, it'll send m+n number of
* events. It receives the list of branches before and after the action.
* For example, if user has "main" and "develop" branches as protected and wants to include "staging" branch as
* protected as well, then oldProtectedBranches will be ["main", "develop"] and newProtectedBranches will be
* ["main", "develop", "staging"]
* @param application Application object of the root application
* @param oldProtectedBranches List of branches that were protected before this action.
* @param newProtectedBranches List of branches that are going to be protected.
* @return An empty Mono
*/
protected Mono<Void> sendBranchProtectionAnalytics(
Application application, List<String> oldProtectedBranches, List<String> newProtectedBranches) {
List<String> itemsAdded = new ArrayList<>(newProtectedBranches); // add all new items
itemsAdded.removeAll(oldProtectedBranches); // remove the items that were present earlier

List<String> itemsRemoved = new ArrayList<>(oldProtectedBranches); // add all old items
itemsRemoved.removeAll(newProtectedBranches); // remove the items that are also present in new list

List<Mono<Application>> eventSenderMonos = new ArrayList<>();

// send an analytics event for each removed branch
for (String branchName : itemsRemoved) {
eventSenderMonos.add(addAnalyticsForGitOperation(GIT_REMOVE_PROTECTED_BRANCH, branchName, application));
}

// send an analytics event for each newly protected branch
for (String branchName : itemsAdded) {
eventSenderMonos.add(addAnalyticsForGitOperation(GIT_ADD_PROTECTED_BRANCH, branchName, application));
}

return Flux.merge(eventSenderMonos).then();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import com.appsmith.server.repositories.CacheableRepositoryHelper;
import com.appsmith.server.repositories.PluginRepository;
import com.appsmith.server.repositories.WorkspaceRepository;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.LayoutActionService;
import com.appsmith.server.services.LayoutCollectionService;
Expand Down Expand Up @@ -118,6 +119,7 @@
import java.util.UUID;
import java.util.stream.Collectors;

import static com.appsmith.external.constants.AnalyticsEvents.GIT_ADD_PROTECTED_BRANCH;
import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_ACTIONS;
Expand All @@ -128,7 +130,11 @@
import static java.lang.Boolean.TRUE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@ExtendWith(SpringExtension.class)
@SpringBootTest
Expand Down Expand Up @@ -227,6 +233,9 @@ public class GitServiceCETest {
@Autowired
CacheableRepositoryHelper cacheableRepositoryHelper;

@SpyBean
AnalyticsService analyticsService;

@BeforeEach
public void setup() throws IOException, GitAPIException {
User currentUser = sessionUserService.getCurrentUser().block();
Expand Down Expand Up @@ -4370,6 +4379,9 @@ public void updateProtectedBranches_WhenListContainsOnlyDefaultBranch_Success()
if (application.getId().equals(defaultAppId)) {
// the default app should have the protected branch list
assertThat(metadata.getBranchProtectionRules()).containsExactly("master");
// the analytics service should be triggered once for this event
verify(analyticsService, times(1))
.sendEvent(eq(GIT_ADD_PROTECTED_BRANCH.getEventName()), anyString(), anyMap());
}
}
})
Expand Down

0 comments on commit 16ddb50

Please sign in to comment.