Search in sources :

Example 6 with Branch

use of org.gitlab4j.api.models.Branch in project legend-sdlc by finos.

the class GitLabWorkspaceApi method getAllWorkspacesByAccessType.

private List<Workspace> getAllWorkspacesByAccessType(String projectId, WorkspaceType workspaceType, ProjectFileAccessProvider.WorkspaceAccessType workspaceAccessType) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(workspaceType, "workspaceType may not be null");
    LegendSDLCServerException.validateNonNull(workspaceAccessType, "workspaceAccessType may not be null");
    try {
        GitLabProjectId gitLabProjectId = parseProjectId(projectId);
        Pager<Branch> pager = getGitLabApi(gitLabProjectId.getGitLabMode()).getRepositoryApi().getBranches(gitLabProjectId.getGitLabId(), ITEMS_PER_PAGE);
        return PagerTools.stream(pager).filter(branch -> (branch != null) && isWorkspaceBranchName(branch.getName(), workspaceType, workspaceAccessType)).map(branch -> workspaceBranchToWorkspace(projectId, branch, workspaceType, workspaceAccessType)).collect(Collectors.toList());
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to get " + workspaceType.getLabel() + " " + workspaceAccessType.getLabelPlural() + " for project " + projectId, () -> "Unknown project: " + projectId, () -> "Error getting " + workspaceType.getLabel() + " " + workspaceAccessType.getLabelPlural() + " for project " + projectId);
    }
}
Also used : Workspace(org.finos.legend.sdlc.domain.model.project.workspace.Workspace) CommitsApi(org.gitlab4j.api.CommitsApi) Arrays(java.util.Arrays) Branch(org.gitlab4j.api.models.Branch) Lists(org.eclipse.collections.api.factory.Lists) LoggerFactory(org.slf4j.LoggerFactory) GitLabUserContext(org.finos.legend.sdlc.server.gitlab.auth.GitLabUserContext) StateEvent(org.gitlab4j.api.Constants.StateEvent) CommitRef(org.gitlab4j.api.models.CommitRef) Inject(javax.inject.Inject) GitLabApiTools(org.finos.legend.sdlc.server.gitlab.tools.GitLabApiTools) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) MergeRequest(org.gitlab4j.api.models.MergeRequest) WorkspaceApi(org.finos.legend.sdlc.server.domain.api.workspace.WorkspaceApi) PagerTools(org.finos.legend.sdlc.server.gitlab.tools.PagerTools) BackgroundTaskProcessor(org.finos.legend.sdlc.server.tools.BackgroundTaskProcessor) Status(javax.ws.rs.core.Response.Status) Commit(org.gitlab4j.api.models.Commit) MergeRequestApi(org.gitlab4j.api.MergeRequestApi) RepositoryApi(org.gitlab4j.api.RepositoryApi) Logger(org.slf4j.Logger) ProjectFileAccessProvider(org.finos.legend.sdlc.server.project.ProjectFileAccessProvider) Constants(org.gitlab4j.api.Constants) Pager(org.gitlab4j.api.Pager) Set(java.util.Set) RevisionApi(org.finos.legend.sdlc.server.domain.api.revision.RevisionApi) Collectors(java.util.stream.Collectors) WorkspaceType(org.finos.legend.sdlc.domain.model.project.workspace.WorkspaceType) RefType(org.gitlab4j.api.models.CommitRef.RefType) CommitAction(org.gitlab4j.api.models.CommitAction) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) CallUntil(org.finos.legend.sdlc.server.tools.CallUntil) List(java.util.List) Diff(org.gitlab4j.api.models.Diff) Stream(java.util.stream.Stream) Revision(org.finos.legend.sdlc.domain.model.revision.Revision) GitLabApiException(org.gitlab4j.api.GitLabApiException) GitLabApi(org.gitlab4j.api.GitLabApi) CompareResults(org.gitlab4j.api.models.CompareResults) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) Branch(org.gitlab4j.api.models.Branch) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException)

Example 7 with Branch

use of org.gitlab4j.api.models.Branch in project legend-sdlc by finos.

the class GitLabWorkspaceApi method createConflictResolution.

/**
 * This method will mark create a conflict resolution branch from a given workspace branch. Assume we have workspace branch `w1`, this method will:
 * 1. Create resolution branch from `master` branch (check if that's the latest)
 * 2. Get all the changes of workspace branch `w1`
 * 3. Copy and replace those changes to resolution branch `w1` and create a new commit out of that.
 */
private WorkspaceUpdateReport createConflictResolution(String projectId, String workspaceId, WorkspaceType workspaceType, String masterRevisionId) {
    // Check if conflict resolution is happening, if it is, it means conflict resolution branch already existed, so we will
    // scrap that branch and create a new one.
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    RepositoryApi repositoryApi = getGitLabApi(gitLabProjectId.getGitLabMode()).getRepositoryApi();
    Branch previousConflictResolutionBranch = null;
    ProjectFileAccessProvider.WorkspaceAccessType conflictResolutionWorkspaceType = ProjectFileAccessProvider.WorkspaceAccessType.CONFLICT_RESOLUTION;
    try {
        previousConflictResolutionBranch = withRetries(() -> repositoryApi.getBranch(gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, conflictResolutionWorkspaceType)));
    } catch (Exception e) {
        if (!GitLabApiTools.isNotFoundGitLabApiException(e)) {
            LOGGER.error("Error updating {} {} in project {}", workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel(), workspaceId, projectId);
        }
    }
    // Delete conflict resolution workspace
    if (previousConflictResolutionBranch != null) {
        LOGGER.debug("Conflict resolution already happened in workspace {} in project {}, but we will recreate this conflict resolution workspace to make sure it's up to date", workspaceId, projectId);
        boolean conflictResolutionBranchDeleted;
        try {
            conflictResolutionBranchDeleted = GitLabApiTools.deleteBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, conflictResolutionWorkspaceType), 20, 1_000);
        } catch (Exception e) {
            throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to delete " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " (" + workspaceId + ") or project (" + projectId + ")", () -> "Error deleting " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
        }
        if (!conflictResolutionBranchDeleted) {
            throw new LegendSDLCServerException("Failed to delete " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
        }
    }
    // Create conflict resolution workspace
    Branch conflictResolutionBranch;
    try {
        conflictResolutionBranch = GitLabApiTools.createBranchFromSourceBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, conflictResolutionWorkspaceType), MASTER_BRANCH, 30, 1_000);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create workspace " + workspaceId + " in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error creating workspace " + workspaceId + " in project " + projectId);
    }
    if (conflictResolutionBranch == null) {
        throw new LegendSDLCServerException("Failed to create " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Get the changes of the current workspace
    String currentWorkspaceRevisionId = this.revisionApi.getWorkspaceRevisionContext(projectId, workspaceId, workspaceType).getCurrentRevision().getId();
    String workspaceCreationRevisionId;
    try {
        workspaceCreationRevisionId = withRetries(() -> repositoryApi.getMergeBase(gitLabProjectId.getGitLabId(), Arrays.asList(MASTER_BRANCH, currentWorkspaceRevisionId)).getId());
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to get merged base revision for revisions " + MASTER_BRANCH + ", " + currentWorkspaceRevisionId + " from project " + projectId, () -> "Could not find revisions " + MASTER_BRANCH + ", " + currentWorkspaceRevisionId + " from project " + projectId, () -> "Failed to fetch merged base information for revisions " + MASTER_BRANCH + ", " + currentWorkspaceRevisionId + " from project " + projectId);
    }
    CompareResults comparisonResult;
    try {
        comparisonResult = withRetries(() -> repositoryApi.compare(gitLabProjectId.getGitLabId(), workspaceCreationRevisionId, currentWorkspaceRevisionId, true));
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to get comparison information from revision " + workspaceCreationRevisionId + "  to revision " + currentWorkspaceRevisionId + " on project" + projectId, () -> "Could not find revisions " + workspaceCreationRevisionId + " ," + currentWorkspaceRevisionId + " on project" + projectId, () -> "Failed to fetch comparison information from revision " + workspaceCreationRevisionId + "  to revision " + currentWorkspaceRevisionId + " on project" + projectId);
    }
    List<Diff> diffs = comparisonResult.getDiffs();
    // Create a new commit on conflict resolution branch
    CommitsApi commitsApi = getGitLabApi(gitLabProjectId.getGitLabMode()).getCommitsApi();
    ProjectFileAccessProvider.FileAccessContext projectFileAccessContext = getProjectFileAccessProvider().getProjectFileAccessContext(projectId);
    ProjectFileAccessProvider.WorkspaceAccessType workspaceAccessType = ProjectFileAccessProvider.WorkspaceAccessType.WORKSPACE;
    ProjectFileAccessProvider.FileAccessContext workspaceFileAccessContext = getProjectFileAccessProvider().getWorkspaceFileAccessContext(projectId, workspaceId, workspaceType, workspaceAccessType);
    try {
        List<CommitAction> commitActions = Lists.mutable.empty();
        // NOTE: we are bringing the diffs from the workspace and applying those diffs to the project HEAD. Now, the project
        // HEAD could potentially differ greatly from the workspace base revision. This means that when we create the commit
        // action from the diff, we must be careful about the action type.
        // Take for example DELETE: if according to the diff, we delete file A, but at project HEAD, A is already deleted
        // in one of the commits between workspace base and project HEAD, such DELETE commit action will fail, this should then be
        // a NO_OP. Then again, we will have to be careful when CREATE, MOVE, and UPDATE.
        diffs.forEach(diff -> {
            if (diff.getDeletedFile()) {
                // Ensure the file to delete exists at project HEAD
                ProjectFileAccessProvider.ProjectFile fileToDelete = projectFileAccessContext.getFile(diff.getOldPath());
                if (fileToDelete != null) {
                    commitActions.add(new CommitAction().withAction(CommitAction.Action.DELETE).withFilePath(diff.getOldPath()));
                }
            } else if (diff.getRenamedFile()) {
                // split a MOVE into a DELETE followed by an CREATE/UPDATE to handle cases when
                // file to be moved is already deleted at project HEAD
                // and file to be moved to is already created at project HEAD
                ProjectFileAccessProvider.ProjectFile fileToDelete = projectFileAccessContext.getFile(diff.getOldPath());
                ProjectFileAccessProvider.ProjectFile fileToReplace = projectFileAccessContext.getFile(diff.getNewPath());
                if (fileToDelete != null) {
                    commitActions.add(new CommitAction().withAction(CommitAction.Action.DELETE).withFilePath(diff.getOldPath()));
                }
                commitActions.add(new CommitAction().withAction(fileToReplace == null ? CommitAction.Action.CREATE : CommitAction.Action.UPDATE).withFilePath(diff.getNewPath()).withEncoding(Constants.Encoding.BASE64).withContent(encodeBase64(workspaceFileAccessContext.getFile(diff.getNewPath()).getContentAsBytes())));
            } else if (diff.getNewFile()) {
                // If the file to be created already exists at project HEAD, change this to an UPDATE
                ProjectFileAccessProvider.ProjectFile fileToCreate = projectFileAccessContext.getFile(diff.getOldPath());
                commitActions.add(new CommitAction().withAction(fileToCreate == null ? CommitAction.Action.CREATE : CommitAction.Action.UPDATE).withFilePath(diff.getNewPath()).withEncoding(Constants.Encoding.BASE64).withContent(encodeBase64(workspaceFileAccessContext.getFile(diff.getNewPath()).getContentAsBytes())));
            } else {
                // File was updated
                // If the file to be updated is deleted at project HEAD, change this to a CREATE
                ProjectFileAccessProvider.ProjectFile fileToUpdate = projectFileAccessContext.getFile(diff.getOldPath());
                commitActions.add(new CommitAction().withAction(fileToUpdate == null ? CommitAction.Action.CREATE : CommitAction.Action.UPDATE).withFilePath(diff.getOldPath()).withEncoding(Constants.Encoding.BASE64).withContent(encodeBase64(workspaceFileAccessContext.getFile(diff.getOldPath()).getContentAsBytes())));
            }
        });
        commitsApi.createCommit(gitLabProjectId.getGitLabId(), this.getWorkspaceBranchName(workspaceId, workspaceType, conflictResolutionWorkspaceType), "aggregated changes for conflict resolution", null, null, getCurrentUser(), commitActions);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create commit on " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + workspaceId + " of project " + projectId, () -> "Unknown project: " + projectId + " or " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId, () -> "Failed to create commit in " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + workspaceId + " of project" + projectId);
    }
    return createWorkspaceUpdateReport(WorkspaceUpdateReportStatus.CONFLICT, masterRevisionId, conflictResolutionBranch.getCommit().getId());
}
Also used : CompareResults(org.gitlab4j.api.models.CompareResults) Diff(org.gitlab4j.api.models.Diff) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException) CommitsApi(org.gitlab4j.api.CommitsApi) ProjectFileAccessProvider(org.finos.legend.sdlc.server.project.ProjectFileAccessProvider) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) Branch(org.gitlab4j.api.models.Branch) RepositoryApi(org.gitlab4j.api.RepositoryApi) CommitAction(org.gitlab4j.api.models.CommitAction)

Example 8 with Branch

use of org.gitlab4j.api.models.Branch in project legend-sdlc by finos.

the class GitLabWorkspaceApi method getWorkspaceByAccessType.

private Workspace getWorkspaceByAccessType(String projectId, String workspaceId, WorkspaceType workspaceType, ProjectFileAccessProvider.WorkspaceAccessType workspaceAccessType) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(workspaceId, "workspaceId may not be null");
    LegendSDLCServerException.validateNonNull(projectId, "workspaceAccessType may not be null");
    try {
        GitLabProjectId gitLabProjectId = parseProjectId(projectId);
        Branch branch = getGitLabApi(gitLabProjectId.getGitLabMode()).getRepositoryApi().getBranch(gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, workspaceAccessType));
        return workspaceBranchToWorkspace(projectId, branch, workspaceType, workspaceAccessType);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to get " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + "  " + workspaceId + " in project " + projectId, () -> "Unknown " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " (" + workspaceId + ") or project (" + projectId + ")", () -> "Error getting " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
}
Also used : GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) Branch(org.gitlab4j.api.models.Branch) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException)

Example 9 with Branch

use of org.gitlab4j.api.models.Branch in project legend-sdlc by finos.

the class GitLabWorkspaceApi method updateWorkspace.

/**
 * There are 4 possible outcome for this method:
 * 1. NO_OP: If the workspace is already branching from the HEAD of master, nothing is needed.
 * 2. UPDATED: If the workspace is not branching from the HEAD of master, and we successfully rebase the branch to master HEAD.
 * 3. CONFLICT: If the workspace is not branching from the HEAD of master, and we failed to rebase the branch to master HEAD due to merge conflicts.
 * 4. ERROR
 * <p>
 * The procedure goes like the followings:
 * 1. Check if the current workspace is already up to date:
 * - If yes, return NO_OP
 * - If no, proceed
 * 2. Create a temp branch to attempt to rebase:
 * - If rebase succeeded, return UPDATED
 * - If rebase failed, further check if we need to enter conflict resolution mode.
 * This check makes sure the conflict that causes rebase to fail does not come from intermediate
 * commits by squashing these commits and attempt to do another rebase there. If this still fails
 * it means the workspace in overall truly has merge conflicts while updating, so entering conflict resolution mode
 */
@Override
public WorkspaceUpdateReport updateWorkspace(String projectId, String workspaceId, WorkspaceType workspaceType) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(workspaceId, "workspaceId may not be null");
    LOGGER.info("Updating workspace {} in project {} to latest revision", workspaceId, projectId);
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    ProjectFileAccessProvider.WorkspaceAccessType workspaceAccessType = ProjectFileAccessProvider.WorkspaceAccessType.WORKSPACE;
    String workspaceBranchName = getBranchName(workspaceId, workspaceType, workspaceAccessType);
    GitLabApi gitLabApi = getGitLabApi(gitLabProjectId.getGitLabMode());
    RepositoryApi repositoryApi = gitLabApi.getRepositoryApi();
    // Get the workspace branch
    Branch workspaceBranch;
    try {
        workspaceBranch = withRetries(() -> repositoryApi.getBranch(gitLabProjectId.getGitLabId(), workspaceBranchName));
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to access " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " in project " + projectId + ": " + workspaceId, () -> "Error accessing " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    String currentWorkspaceRevisionId = workspaceBranch.getCommit().getId();
    LOGGER.info("Found latest revision of {} {} in project {}: {}", workspaceType.getLabel() + " " + workspaceAccessType.getLabel(), workspaceId, projectId, currentWorkspaceRevisionId);
    // Determine the revision to update to
    Branch masterBranch;
    try {
        masterBranch = withRetries(() -> repositoryApi.getBranch(gitLabProjectId.getGitLabId(), MASTER_BRANCH));
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to access the latest revision in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error accessing latest revision for project " + projectId);
    }
    String masterRevisionId = masterBranch.getCommit().getId();
    LOGGER.info("Found latest revision of project {}: {}", projectId, masterRevisionId);
    CommitsApi commitsApi = gitLabApi.getCommitsApi();
    // Check if the workspace already has the latest revision
    try {
        boolean isAlreadyLatest = false;
        // This will check if the branch contains the master HEAD commit by looking up the list of references the commit is pushed to
        if (masterRevisionId.equals(currentWorkspaceRevisionId)) {
            isAlreadyLatest = true;
        } else {
            Pager<CommitRef> masterHeadCommitRefPager = withRetries(() -> commitsApi.getCommitRefs(gitLabProjectId.getGitLabId(), masterRevisionId, RefType.BRANCH, ITEMS_PER_PAGE));
            Stream<CommitRef> masterHeadCommitRefs = PagerTools.stream(masterHeadCommitRefPager);
            if (masterHeadCommitRefs.anyMatch(cr -> workspaceBranchName.equals(cr.getName()))) {
                isAlreadyLatest = true;
            }
        }
        if (isAlreadyLatest) {
            // revision is already in the workspace, no update necessary, hence NO_OP
            LOGGER.info("Workspace {} in project {} already has revision {}, no update necessary", workspaceId, projectId, masterRevisionId);
            return createWorkspaceUpdateReport(WorkspaceUpdateReportStatus.NO_OP, masterRevisionId, currentWorkspaceRevisionId);
        }
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to access revision " + masterRevisionId + " in project " + projectId, () -> "Unknown revision in project " + projectId + ": " + masterRevisionId, () -> "Error accessing revision " + masterRevisionId + " of project " + projectId);
    }
    // Temp branch for checking for merge conflicts
    String tempBranchName = newUserTemporaryBranchName();
    Branch tempBranch;
    try {
        tempBranch = GitLabApiTools.createBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), tempBranchName, currentWorkspaceRevisionId, 30, 1_000);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create temporary workspace " + tempBranchName + " in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error creating temporary workspace " + tempBranchName + " in project " + projectId);
    }
    if (tempBranch == null) {
        throw new LegendSDLCServerException("Failed to create temporary workspace " + tempBranchName + " in project " + projectId + " from revision " + currentWorkspaceRevisionId);
    }
    // Attempt to rebase the temporary branch on top of master
    boolean rebaseSucceeded = this.attemptToRebaseWorkspaceUsingTemporaryBranch(projectId, workspaceId, workspaceType, tempBranchName, masterRevisionId);
    // 2. There are merge conflicts, so we enter conflict resolution route
    if (!rebaseSucceeded) {
        String workspaceCreationRevisionId;
        try {
            workspaceCreationRevisionId = withRetries(() -> repositoryApi.getMergeBase(gitLabProjectId.getGitLabId(), Arrays.asList(MASTER_BRANCH, currentWorkspaceRevisionId)).getId());
        } catch (Exception e) {
            throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to get merged base revision for workspace " + workspaceId + " from project " + projectId, () -> "Could not find revision " + currentWorkspaceRevisionId + " from project " + projectId, () -> "Failed to fetch merged base revision for workspace " + workspaceId + " from project " + projectId);
        }
        // Small optimization step to make sure we need squashing.
        // If there are less than 2 commits (not including the base commit), there is no point in squashing
        List<Revision> latestTwoRevisionsOnWorkspaceBranch = this.revisionApi.getWorkspaceRevisionContext(projectId, workspaceId, workspaceType).getRevisions(null, null, null, 2);
        Set<String> latestTwoRevisionOnWorkspaceBranchIds = latestTwoRevisionsOnWorkspaceBranch.stream().map(Revision::getId).collect(Collectors.toSet());
        if (latestTwoRevisionOnWorkspaceBranchIds.contains(workspaceCreationRevisionId)) {
            LOGGER.debug("Failed to rebase branch {}, but the branch does not have enough commits to perform squashing. Proceeding to conflict resolution...", workspaceBranchName);
            return this.createConflictResolution(projectId, workspaceId, workspaceType, masterRevisionId);
        } else {
            LOGGER.debug("Failed to rebase branch {}. Performing squashing commits and re-attempting rebase...", workspaceBranchName);
        }
        WorkspaceUpdateReport rebaseUpdateAttemptReport = this.attemptToSquashAndRebaseWorkspace(projectId, workspaceId, workspaceType, masterRevisionId, currentWorkspaceRevisionId, workspaceCreationRevisionId);
        return WorkspaceUpdateReportStatus.UPDATED.equals(rebaseUpdateAttemptReport.getStatus()) ? rebaseUpdateAttemptReport : this.createConflictResolution(projectId, workspaceId, workspaceType, masterRevisionId);
    }
    String updatedCurrentWorkspaceRevisionId = this.revisionApi.getWorkspaceRevisionContext(projectId, workspaceId, workspaceType).getCurrentRevision().getId();
    return createWorkspaceUpdateReport(WorkspaceUpdateReportStatus.UPDATED, masterRevisionId, updatedCurrentWorkspaceRevisionId);
}
Also used : GitLabApi(org.gitlab4j.api.GitLabApi) CommitRef(org.gitlab4j.api.models.CommitRef) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException) CommitsApi(org.gitlab4j.api.CommitsApi) ProjectFileAccessProvider(org.finos.legend.sdlc.server.project.ProjectFileAccessProvider) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) Revision(org.finos.legend.sdlc.domain.model.revision.Revision) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) Branch(org.gitlab4j.api.models.Branch) RepositoryApi(org.gitlab4j.api.RepositoryApi)

Example 10 with Branch

use of org.gitlab4j.api.models.Branch in project legend-sdlc by finos.

the class GitLabConflictResolutionApi method discardChangesConflictResolution.

/**
 * This method will discard all changes in conflict resolution. Assume we have workspace branch `w1`, this method will:
 * 1. Remove conflict resolution branch of `w1`
 * 2. Create backup branch for `w1`
 * 3. Remove `w1`
 * 4. Create `w1` from project head
 * 5. Remove backup branch for `w1`
 */
@Override
public void discardChangesConflictResolution(String projectId, String workspaceId, WorkspaceType workspaceType) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(workspaceId, "workspaceId may not be null");
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    RepositoryApi repositoryApi = getGitLabApi(gitLabProjectId.getGitLabMode()).getRepositoryApi();
    ProjectFileAccessProvider.WorkspaceAccessType conflictResolutionWorkspaceType = ProjectFileAccessProvider.WorkspaceAccessType.CONFLICT_RESOLUTION;
    // Verify conflict resolution is happening
    try {
        withRetries(() -> repositoryApi.getBranch(gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, conflictResolutionWorkspaceType)));
    } catch (Exception e) {
        if (GitLabApiTools.isNotFoundGitLabApiException(e)) {
            LOGGER.error("Conflict resolution is not happening on {} {} in project {}, so discard changes is not actionable", workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel(), workspaceId, projectId);
        }
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to get " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " (" + workspaceId + ") or project (" + projectId + "). " + "This implies that conflict resolution is not taking place, hence discard changes is not actionable", () -> "Error getting " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Delete backup branch if already exists
    boolean backupWorkspaceDeleted;
    ProjectFileAccessProvider.WorkspaceAccessType backupWorkspaceType = ProjectFileAccessProvider.WorkspaceAccessType.BACKUP;
    try {
        backupWorkspaceDeleted = GitLabApiTools.deleteBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, backupWorkspaceType), 20, 1_000);
    } catch (Exception e) {
        // If we fail to delete the residual backup workspace, we cannot proceed anyway, so we will throw the error here
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to delete " + workspaceType.getLabel() + " " + backupWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error deleting " + workspaceType.getLabel() + " " + backupWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    if (!backupWorkspaceDeleted) {
        throw new LegendSDLCServerException("Failed to delete " + workspaceType.getLabel() + " " + backupWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Create backup branch
    Branch workspaceBranch;
    ProjectFileAccessProvider.WorkspaceAccessType workspaceAccessType = ProjectFileAccessProvider.WorkspaceAccessType.WORKSPACE;
    try {
        workspaceBranch = GitLabApiTools.createBranchFromSourceBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, backupWorkspaceType), getWorkspaceBranchName(workspaceId, workspaceType, workspaceAccessType), 30, 1_000);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create " + workspaceType.getLabel() + " " + backupWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error creating " + workspaceType.getLabel() + " " + backupWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    if (workspaceBranch == null) {
        throw new LegendSDLCServerException("Failed to create " + workspaceType.getLabel() + " " + backupWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Delete original branch
    boolean originalBranchDeleted;
    try {
        originalBranchDeleted = GitLabApiTools.deleteBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, workspaceAccessType), 20, 1_000);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to delete " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " (" + workspaceId + ") or project (" + projectId + ")", () -> "Error deleting " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    if (!originalBranchDeleted) {
        throw new LegendSDLCServerException("Failed to delete " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Create new workspace branch off the project HEAD
    Branch newWorkspaceBranch;
    try {
        newWorkspaceBranch = GitLabApiTools.createBranchFromSourceBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, workspaceAccessType), MASTER_BRANCH, 30, 1_000);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error creating " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    if (newWorkspaceBranch == null) {
        throw new LegendSDLCServerException("Failed to create " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Delete conflict resolution branch
    boolean conflictResolutionWorkspaceDeleted;
    try {
        conflictResolutionWorkspaceDeleted = GitLabApiTools.deleteBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, conflictResolutionWorkspaceType), 20, 1_000);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to delete " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " (" + workspaceId + ") or project (" + projectId + ")", () -> "Error deleting " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    if (!conflictResolutionWorkspaceDeleted) {
        throw new LegendSDLCServerException("Failed to delete " + workspaceType.getLabel() + " " + conflictResolutionWorkspaceType.getLabel() + " " + workspaceId + " in project " + projectId);
    }
    // Delete backup branch
    try {
        boolean deleted = GitLabApiTools.deleteBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, backupWorkspaceType), 20, 1_000);
        if (!deleted) {
            LOGGER.error("Failed to delete {} {} in project {}", workspaceType.getLabel() + " " + backupWorkspaceType.getLabel(), workspaceId, projectId);
        }
    } catch (Exception e) {
        // unfortunate, but this should not throw error
        LOGGER.error("Error deleting {} {} in project {}", workspaceType.getLabel() + " " + backupWorkspaceType.getLabel(), workspaceId, projectId, e);
    }
}
Also used : ProjectFileAccessProvider(org.finos.legend.sdlc.server.project.ProjectFileAccessProvider) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) Branch(org.gitlab4j.api.models.Branch) RepositoryApi(org.gitlab4j.api.RepositoryApi) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException)

Aggregations

Branch (org.gitlab4j.api.models.Branch)18 LegendSDLCServerException (org.finos.legend.sdlc.server.error.LegendSDLCServerException)15 GitLabApiException (org.gitlab4j.api.GitLabApiException)15 GitLabProjectId (org.finos.legend.sdlc.server.gitlab.GitLabProjectId)14 RepositoryApi (org.gitlab4j.api.RepositoryApi)14 ProjectFileAccessProvider (org.finos.legend.sdlc.server.project.ProjectFileAccessProvider)12 CommitsApi (org.gitlab4j.api.CommitsApi)6 GitLabApi (org.gitlab4j.api.GitLabApi)6 Revision (org.finos.legend.sdlc.domain.model.revision.Revision)4 Commit (org.gitlab4j.api.models.Commit)4 CommitAction (org.gitlab4j.api.models.CommitAction)4 CommitRef (org.gitlab4j.api.models.CommitRef)4 CompareResults (org.gitlab4j.api.models.CompareResults)4 MergeRequest (org.gitlab4j.api.models.MergeRequest)4 MergeRequestApi (org.gitlab4j.api.MergeRequestApi)3 Diff (org.gitlab4j.api.models.Diff)3 Arrays (java.util.Arrays)2 List (java.util.List)2 Objects (java.util.Objects)2 Set (java.util.Set)2