com.google.gerrit.server.git.BanCommit.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.server.git.BanCommit.java

Source

// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.git;

import static com.google.gerrit.reviewdb.client.RefNames.REFS_REJECT_COMMITS;

import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.project.ProjectControl;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.notes.Note;
import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

@Singleton
public class BanCommit {
    /**
     * Loads a list of commits to reject from {@code refs/meta/reject-commits}.
     *
     * @param repo repository from which the rejected commits should be loaded
     * @param walk open revwalk on repo.
     * @return NoteMap of commits to be rejected, null if there are none.
     * @throws IOException the map cannot be loaded.
     */
    public static NoteMap loadRejectCommitsMap(Repository repo, RevWalk walk) throws IOException {
        try {
            Ref ref = repo.getRefDatabase().exactRef(RefNames.REFS_REJECT_COMMITS);
            if (ref == null) {
                return NoteMap.newEmptyMap();
            }

            RevCommit map = walk.parseCommit(ref.getObjectId());
            return NoteMap.read(walk.getObjectReader(), map);
        } catch (IOException badMap) {
            throw new IOException("Cannot load " + RefNames.REFS_REJECT_COMMITS, badMap);
        }
    }

    private final Provider<IdentifiedUser> currentUser;
    private final GitRepositoryManager repoManager;
    private final TimeZone tz;
    private NotesBranchUtil.Factory notesBranchUtilFactory;

    @Inject
    BanCommit(final Provider<IdentifiedUser> currentUser, final GitRepositoryManager repoManager,
            @GerritPersonIdent final PersonIdent gerritIdent,
            final NotesBranchUtil.Factory notesBranchUtilFactory) {
        this.currentUser = currentUser;
        this.repoManager = repoManager;
        this.notesBranchUtilFactory = notesBranchUtilFactory;
        this.tz = gerritIdent.getTimeZone();
    }

    public BanCommitResult ban(final ProjectControl projectControl, final List<ObjectId> commitsToBan,
            final String reason) throws PermissionDeniedException, IOException, ConcurrentRefUpdateException {
        if (!projectControl.isOwner()) {
            throw new PermissionDeniedException("Not project owner: not permitted to ban commits");
        }

        final BanCommitResult result = new BanCommitResult();
        NoteMap banCommitNotes = NoteMap.newEmptyMap();
        // Add a note for each banned commit to notes.
        final Project.NameKey project = projectControl.getProject().getNameKey();
        try (Repository repo = repoManager.openRepository(project);
                RevWalk revWalk = new RevWalk(repo);
                ObjectInserter inserter = repo.newObjectInserter()) {
            ObjectId noteId = null;
            for (final ObjectId commitToBan : commitsToBan) {
                try {
                    revWalk.parseCommit(commitToBan);
                } catch (MissingObjectException e) {
                    // Ignore exception, non-existing commits can be banned.
                } catch (IncorrectObjectTypeException e) {
                    result.notACommit(commitToBan);
                    continue;
                }
                if (noteId == null) {
                    noteId = createNoteContent(reason, inserter);
                }
                banCommitNotes.set(commitToBan, noteId);
            }
            NotesBranchUtil notesBranchUtil = notesBranchUtilFactory.create(project, repo, inserter);
            NoteMap newlyCreated = notesBranchUtil.commitNewNotes(banCommitNotes, REFS_REJECT_COMMITS,
                    createPersonIdent(), buildCommitMessage(commitsToBan, reason));

            for (Note n : banCommitNotes) {
                if (newlyCreated.contains(n)) {
                    result.commitBanned(n);
                } else {
                    result.commitAlreadyBanned(n);
                }
            }
            return result;
        }
    }

    private ObjectId createNoteContent(String reason, ObjectInserter inserter)
            throws UnsupportedEncodingException, IOException {
        String noteContent = reason != null ? reason : "";
        if (noteContent.length() > 0 && !noteContent.endsWith("\n")) {
            noteContent = noteContent + "\n";
        }
        return inserter.insert(Constants.OBJ_BLOB, noteContent.getBytes("UTF-8"));
    }

    private PersonIdent createPersonIdent() {
        Date now = new Date();
        return currentUser.get().newCommitterIdent(now, tz);
    }

    private static String buildCommitMessage(final List<ObjectId> bannedCommits, final String reason) {
        final StringBuilder commitMsg = new StringBuilder();
        commitMsg.append("Banning ");
        commitMsg.append(bannedCommits.size());
        commitMsg.append(" ");
        commitMsg.append(bannedCommits.size() == 1 ? "commit" : "commits");
        commitMsg.append("\n\n");
        if (reason != null) {
            commitMsg.append("Reason: ");
            commitMsg.append(reason);
            commitMsg.append("\n\n");
        }
        commitMsg.append("The following commits are banned:\n");
        final StringBuilder commitList = new StringBuilder();
        for (final ObjectId c : bannedCommits) {
            if (commitList.length() > 0) {
                commitList.append(",\n");
            }
            commitList.append(c.getName());
        }
        commitMsg.append(commitList);
        return commitMsg.toString();
    }
}