Search in sources :

Example 6 with MergeRequest

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

the class GitLabReviewApi method getReviewUpdateStatus.

@Override
public ReviewUpdateStatus getReviewUpdateStatus(String projectId, String reviewId) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(reviewId, "reviewId may not be null");
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    GitLabApi gitLabApi = getGitLabApi(gitLabProjectId.getGitLabMode());
    MergeRequest mergeRequest = getReviewMergeRequest(gitLabApi.getMergeRequestApi(), gitLabProjectId, reviewId);
    if (!(isOpen(mergeRequest) || isLocked(mergeRequest))) {
        throw new LegendSDLCServerException("Cannot get update status for review " + mergeRequest.getIid() + " in project " + projectId + ": state is " + getReviewState(mergeRequest), Status.CONFLICT);
    }
    return getReviewUpdateStatus(gitLabProjectId, gitLabApi, mergeRequest);
}
Also used : GitLabApi(org.gitlab4j.api.GitLabApi) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) MergeRequest(org.gitlab4j.api.models.MergeRequest) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId)

Example 7 with MergeRequest

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

the class GitLabReviewApi method approveReview.

@Override
public Review approveReview(String projectId, String reviewId) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(reviewId, "reviewId may not be null");
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    MergeRequestApi mergeRequestApi = getGitLabApi(gitLabProjectId.getGitLabMode()).getMergeRequestApi();
    MergeRequest mergeRequest = getReviewMergeRequest(mergeRequestApi, gitLabProjectId, reviewId);
    try {
        MergeRequest approvalMergeRequest = mergeRequestApi.approveMergeRequest(gitLabProjectId.getGitLabId(), mergeRequest.getIid(), mergeRequest.getSha());
        // The MergeRequest that comes back from the approveMergeRequest call is not adequate for
        // creating a Review, as most relevant properties are null. The only useful thing we get
        // from it is the last update time.
        mergeRequest.setUpdatedAt(approvalMergeRequest.getUpdatedAt());
        return fromGitLabMergeRequest(projectId, mergeRequest);
    } catch (GitLabApiException e) {
        switch(e.getHttpStatus()) {
            // Status 401 (Unauthorized) can indicate either that the user is not properly authenticated or that the user is not a valid approver for the merge request.
            case 401:
            case 403:
                {
                    throw new LegendSDLCServerException("User " + getCurrentUser() + " is not allowed to approve review " + reviewId + " in project " + projectId, Status.FORBIDDEN, e);
                }
            case 404:
                {
                    throw new LegendSDLCServerException("Unknown review in project " + projectId + ": " + reviewId, Status.NOT_FOUND, e);
                }
            default:
                {
                    StringBuilder builder = new StringBuilder("Error approving review ").append(reviewId).append(" in project ").append(projectId);
                    String eMessage = e.getMessage();
                    if (eMessage != null) {
                        builder.append(": ").append(eMessage);
                    }
                    throw new LegendSDLCServerException(builder.toString(), e);
                }
        }
    } catch (LegendSDLCServerException e) {
        throw e;
    } catch (Exception e) {
        StringBuilder builder = new StringBuilder("Error approving review ").append(reviewId).append(" in project ").append(projectId);
        String eMessage = e.getMessage();
        if (eMessage != null) {
            builder.append(": ").append(eMessage);
        }
        throw new LegendSDLCServerException(builder.toString(), e);
    }
}
Also used : LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) MergeRequest(org.gitlab4j.api.models.MergeRequest) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) MergeRequestApi(org.gitlab4j.api.MergeRequestApi) GitLabApiException(org.gitlab4j.api.GitLabApiException) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException)

Example 8 with MergeRequest

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

the class GitLabReviewApi method updateReview.

@Override
public ReviewUpdateStatus updateReview(String projectId, String reviewId) {
    LegendSDLCServerException.validateNonNull(projectId, "projectId may not be null");
    LegendSDLCServerException.validateNonNull(reviewId, "reviewId may not be null");
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    GitLabApi gitLabApi = getGitLabApi(gitLabProjectId.getGitLabMode());
    MergeRequestApi mergeRequestApi = gitLabApi.getMergeRequestApi();
    // Check the current status of the review
    MergeRequest initialMergeRequest = getReviewMergeRequest(mergeRequestApi, gitLabProjectId, reviewId);
    if (!isOpen(initialMergeRequest)) {
        throw new LegendSDLCServerException("Only open reviews can be updated: state of review " + initialMergeRequest.getIid() + " in project " + projectId + " is " + getReviewState(initialMergeRequest), Status.CONFLICT);
    }
    ReviewUpdateStatus updateStatus = getReviewUpdateStatus(gitLabProjectId, gitLabApi, initialMergeRequest);
    if (updateStatus.isUpdateInProgress() || ((updateStatus.getBaseRevisionId() != null) && updateStatus.getBaseRevisionId().equals(updateStatus.getTargetRevisionId()))) {
        // Update in progress or already up to date: no need to update
        return updateStatus;
    }
    // Start update attempt
    MergeRequest rebaseMergeRequest;
    try {
        CallUntil<MergeRequest, GitLabApiException> callUntil = CallUntil.callUntil(() -> withRetries(() -> mergeRequestApi.rebaseMergeRequest(gitLabProjectId.getGitLabId(), initialMergeRequest.getIid())), MergeRequest::getRebaseInProgress, 3, 500L);
        if (!callUntil.succeeded()) {
            throw new LegendSDLCServerException("Failed to start update for review " + reviewId + " in project " + projectId);
        }
        rebaseMergeRequest = callUntil.getResult();
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to update review " + reviewId + " in project " + projectId, () -> "Unknown review in project " + projectId + ": " + reviewId, () -> "Error updating review " + reviewId + " in project " + projectId);
    }
    return getReviewUpdateStatus(gitLabProjectId, gitLabApi, rebaseMergeRequest);
}
Also used : GitLabApi(org.gitlab4j.api.GitLabApi) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) MergeRequest(org.gitlab4j.api.models.MergeRequest) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) MergeRequestApi(org.gitlab4j.api.MergeRequestApi) GitLabApiException(org.gitlab4j.api.GitLabApiException) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException)

Example 9 with MergeRequest

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

the class GitLabWorkspaceApi method attemptToRebaseWorkspaceUsingTemporaryBranch.

/**
 * This method attempts to rebase the workspace branch on top of master by using a temp branch. Detailed procedure outlined below:
 * 1. Create a new merge request (MR) that merges temp branch into master branch so that we can use gitlab rebase functionality
 * 2. Call rebase.
 * 3. Continuously check the rebase status of the merge request:
 * - If failed -> return `false`
 * - If succeeded, proceed
 * 4. Re-create workspace branch on top of the rebased temp branch.
 * 5. Cleanup: remove the temp branch and the MR
 * 6. Return `true`
 *
 * @return a boolean flag indicating if the attempted rebase succeeded.
 */
private boolean attemptToRebaseWorkspaceUsingTemporaryBranch(String projectId, String workspaceId, WorkspaceType workspaceType, String tempBranchName, String masterRevisionId) {
    GitLabProjectId gitLabProjectId = parseProjectId(projectId);
    GitLabApi gitLabApi = getGitLabApi(gitLabProjectId.getGitLabMode());
    RepositoryApi repositoryApi = gitLabApi.getRepositoryApi();
    // Create merge request to rebase
    MergeRequestApi mergeRequestApi = getGitLabApi(gitLabProjectId.getGitLabMode()).getMergeRequestApi();
    String title = "Update workspace " + workspaceId;
    String message = "Update workspace " + workspaceId + " up to revision " + masterRevisionId;
    MergeRequest mergeRequest;
    try {
        mergeRequest = mergeRequestApi.createMergeRequest(gitLabProjectId.getGitLabId(), tempBranchName, MASTER_BRANCH, title, message, null, null, null, null, false, false);
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create merge request in project " + projectId, () -> "Unknown branch in project " + projectId + ": " + tempBranchName, () -> "Error creating merge request in project " + projectId);
    }
    // Attempt to rebase the merge request
    try {
        mergeRequestApi.rebaseMergeRequest(gitLabProjectId.getGitLabId(), mergeRequest.getIid());
        // Check rebase status
        // This only throws when we have 403, so we need to keep polling till we know the result
        // See https://docs.gitlab.com/ee/api/merge_requests.html#rebase-a-merge-request
        CallUntil<MergeRequest, GitLabApiException> rebaseStatusCallUntil = CallUntil.callUntil(() -> withRetries(() -> mergeRequestApi.getRebaseStatus(gitLabProjectId.getGitLabId(), mergeRequest.getIid())), mr -> !mr.getRebaseInProgress(), 600, 1000L);
        if (!rebaseStatusCallUntil.succeeded()) {
            LOGGER.warn("Timeout waiting for merge request " + mergeRequest.getIid() + " in project " + projectId + " to finish rebasing");
            return false;
        }
        // Check if there is merge conflict
        if (rebaseStatusCallUntil.getResult().getMergeError() != null) {
            return false;
        } else // if there are no merge conflicts, proceed with the update
        {
            // Create backup branch
            Branch backupBranch;
            ProjectFileAccessProvider.WorkspaceAccessType backupWorkspaceAccessType = ProjectFileAccessProvider.WorkspaceAccessType.BACKUP;
            ProjectFileAccessProvider.WorkspaceAccessType workspaceAccessType = ProjectFileAccessProvider.WorkspaceAccessType.WORKSPACE;
            try {
                backupBranch = GitLabApiTools.createBranchFromSourceBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, backupWorkspaceAccessType), getWorkspaceBranchName(workspaceId, workspaceType, workspaceAccessType), 30, 1_000);
            } catch (Exception e) {
                throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to create " + workspaceType.getLabel() + " " + backupWorkspaceAccessType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId, () -> "Unknown project: " + projectId, () -> "Error creating " + workspaceType.getLabel() + " " + backupWorkspaceAccessType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
            }
            if (backupBranch == null) {
                throw new LegendSDLCServerException("Failed to create " + workspaceType.getLabel() + " " + backupWorkspaceAccessType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " from " + workspaceType.getLabel() + " " + workspaceAccessType.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, () -> "Error while attempting to update the workspace " + workspaceId + " in project " + projectId + ": user " + getCurrentUser() + " is not allowed to delete workspace", () -> "Error while attempting to update the workspace " + workspaceId + " in project " + projectId + ": unknown workspace or project", () -> "Error while attempting to update the workspace " + workspaceId + " in project " + projectId + ": error deleting workspace");
            }
            if (!originalBranchDeleted) {
                throw new LegendSDLCServerException("Failed to delete " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " in project " + projectId);
            }
            // Create new workspace branch off the temp branch head
            Branch newWorkspaceBranch;
            try {
                newWorkspaceBranch = GitLabApiTools.createBranchFromSourceBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, workspaceAccessType), tempBranchName, 30, 1_000);
            } catch (Exception e) {
                throw buildException(e, () -> "Error while attempting to update the workspace " + workspaceId + " in project " + projectId + ": user " + getCurrentUser() + " is not allowed to create workspace", () -> "Error while attempting to update the workspace " + workspaceId + " in project " + projectId + ": unknown project: " + projectId, () -> "Error while attempting to update the workspace " + workspaceId + " in project " + projectId + ": error creating workspace");
            }
            if (newWorkspaceBranch == null) {
                throw new LegendSDLCServerException("Failed to create " + workspaceType.getLabel() + " " + workspaceAccessType.getLabel() + " " + workspaceId + " from temporary workspace " + tempBranchName + " in project " + projectId);
            }
            // Delete backup branch
            try {
                boolean deleted = GitLabApiTools.deleteBranchAndVerify(repositoryApi, gitLabProjectId.getGitLabId(), getWorkspaceBranchName(workspaceId, workspaceType, backupWorkspaceAccessType), 20, 1_000);
                if (!deleted) {
                    LOGGER.error("Failed to delete {} {} in project {}", workspaceType.getLabel() + " " + backupWorkspaceAccessType.getLabel() + " " + workspaceAccessType.getLabel(), workspaceId, projectId);
                }
            } catch (Exception e) {
                // unfortunate, but this should not throw error
                LOGGER.error("Error deleting {} {} in project {}", workspaceType.getLabel() + " " + backupWorkspaceAccessType.getLabel() + " " + workspaceAccessType.getLabel(), workspaceId, projectId);
            }
        }
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to rebase merge request " + mergeRequest.getIid() + " in project " + projectId, () -> "Unknown merge request ( " + mergeRequest.getIid() + " ) or project ( " + projectId + " )", () -> "Error rebasing merge request " + mergeRequest.getIid() + " in project " + projectId);
    } finally {
        // Try to close merge request
        try {
            mergeRequestApi.updateMergeRequest(gitLabProjectId.getGitLabId(), mergeRequest.getIid(), null, title, null, null, StateEvent.CLOSE, null, null, null, null, null, null);
        } catch (Exception closeEx) {
            // if we fail, log the error but we don't throw it
            LOGGER.error("Could not close merge request {} for project {}: {}", mergeRequest.getIid(), projectId, mergeRequest.getWebUrl(), closeEx);
        }
        // Delete temporary branch in the background
        submitBackgroundRetryableTask(() -> waitForPipelinesDeleteBranchAndVerify(gitLabApi, gitLabProjectId, tempBranchName), 5000L, "delete " + tempBranchName);
    }
    return true;
}
Also used : GitLabApi(org.gitlab4j.api.GitLabApi) GitLabApiException(org.gitlab4j.api.GitLabApiException) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException) ProjectFileAccessProvider(org.finos.legend.sdlc.server.project.ProjectFileAccessProvider) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) MergeRequest(org.gitlab4j.api.models.MergeRequest) GitLabProjectId(org.finos.legend.sdlc.server.gitlab.GitLabProjectId) Branch(org.gitlab4j.api.models.Branch) MergeRequestApi(org.gitlab4j.api.MergeRequestApi) RepositoryApi(org.gitlab4j.api.RepositoryApi)

Example 10 with MergeRequest

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

the class BaseGitLabApi method getReviewMergeRequest.

protected MergeRequest getReviewMergeRequest(MergeRequestApi mergeRequestApi, GitLabProjectId projectId, String reviewId, boolean includeRebaseInProgress) {
    int mergeRequestId = parseIntegerId(reviewId);
    MergeRequest mergeRequest;
    try {
        mergeRequest = withRetries(() -> mergeRequestApi.getMergeRequest(projectId.getGitLabId(), mergeRequestId, false, null, includeRebaseInProgress));
    } catch (Exception e) {
        throw buildException(e, () -> "User " + getCurrentUser() + " is not allowed to access review " + reviewId + " in project " + projectId, () -> "Unknown review in project " + projectId + ": " + reviewId, () -> "Error accessing review " + reviewId + " in project " + projectId);
    }
    if (!isReviewMergeRequest(mergeRequest)) {
        throw new LegendSDLCServerException("Unknown review in project " + projectId + ": " + reviewId, Status.NOT_FOUND);
    }
    return mergeRequest;
}
Also used : LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) MergeRequest(org.gitlab4j.api.models.MergeRequest) LegendSDLCServerException(org.finos.legend.sdlc.server.error.LegendSDLCServerException) GitLabApiException(org.gitlab4j.api.GitLabApiException) GitLabAuthException(org.finos.legend.sdlc.server.gitlab.auth.GitLabAuthException)

Aggregations

MergeRequest (org.gitlab4j.api.models.MergeRequest)32 GitLabProjectId (org.finos.legend.sdlc.server.gitlab.GitLabProjectId)25 LegendSDLCServerException (org.finos.legend.sdlc.server.error.LegendSDLCServerException)22 GitLabApiException (org.gitlab4j.api.GitLabApiException)17 MergeRequestApi (org.gitlab4j.api.MergeRequestApi)15 RepositoryApi (org.gitlab4j.api.RepositoryApi)9 ProjectFileAccessProvider (org.finos.legend.sdlc.server.project.ProjectFileAccessProvider)7 DiffRef (org.gitlab4j.api.models.DiffRef)7 Response (javax.ws.rs.core.Response)6 GitLabApi (org.gitlab4j.api.GitLabApi)6 List (java.util.List)5 Form (javax.ws.rs.core.Form)5 Project (org.finos.legend.sdlc.domain.model.project.Project)5 ProjectType (org.finos.legend.sdlc.domain.model.project.ProjectType)5 Review (org.finos.legend.sdlc.domain.model.review.Review)5 Entity (org.finos.legend.sdlc.domain.model.entity.Entity)4 Workspace (org.finos.legend.sdlc.domain.model.project.workspace.Workspace)4 ProjectStructure (org.finos.legend.sdlc.server.project.ProjectStructure)2 Branch (org.gitlab4j.api.models.Branch)2 MergeRequestParams (org.gitlab4j.api.models.MergeRequestParams)2