io.fd.maintainer.plugin.service.MaintainersProvider.java Source code

Java tutorial

Introduction

Here is the source code for io.fd.maintainer.plugin.service.MaintainersProvider.java

Source

/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 *
 * 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 io.fd.maintainer.plugin.service;

import static java.lang.String.format;
import static java.util.Objects.nonNull;

import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import io.fd.maintainer.plugin.parser.ComponentInfo;
import io.fd.maintainer.plugin.parser.MaintainerMismatchException;
import io.fd.maintainer.plugin.parser.MaintainersParser;
import io.fd.maintainer.plugin.service.dto.PluginBranchSpecificSettings;
import io.fd.maintainer.plugin.util.ClosestMatch;
import io.fd.maintainer.plugin.util.PatchListProcessing;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class MaintainersProvider implements ClosestMatch, PatchListProcessing {

    private static final Logger LOG = LoggerFactory.getLogger(MaintainersProvider.class);
    final MaintainersParser maintainersParser;
    @Inject
    private GitRepositoryManager manager;
    @Inject
    private SettingsProvider settingsProvider;
    @Inject
    private SchemaFactory<ReviewDb> schemaFactory;

    public MaintainersProvider() {
        maintainersParser = new MaintainersParser();
    }

    @Nonnull
    public List<ComponentInfo> getMaintainersInfo(@Nonnull final String branchName, final int changeNumber) {

        // get configuration for branch of change
        final PluginBranchSpecificSettings settings = settingsProvider.getBranchSpecificSettings(branchName);

        try (final ReviewDb reviewDb = schemaFactory.open()) {
            final Change change = reviewDb.changes().get(new Change.Id(changeNumber));
            final String fullFileRef = settings.fullFileRef();

            try (final Repository repository = manager.openRepository(change.getProject())) {

                final Ref ref = Optional.ofNullable(repository.findRef(fullFileRef))
                        .orElseThrow(() -> new IllegalStateException(format("Unable to get ref %s", fullFileRef)));

                final RevCommit revCommit = new RevWalk(repository).parseCommit(ref.getObjectId());

                final String maintainersFileContent = findMostRecentMaintainersChangeContent(
                        settings.getLocalFilePath(), repository, new RevWalk(repository), revCommit);

                if (nonNull(maintainersFileContent)) {
                    return maintainersParser.parseMaintainers(maintainersFileContent);
                } else {
                    throw new IllegalStateException(format("Unable to find file %s in branch %s",
                            settings.getLocalFilePath(), fullFileRef));
                }
            } catch (IOException | MaintainerMismatchException e) {
                throw new IllegalStateException(e);
            }

        } catch (OrmException e) {
            throw new IllegalStateException(e);
        }
    }

    // skips head commit
    private String findMostRecentMaintainersChangeContent(final String maintainersFileName,
            final Repository repository, final RevWalk revWalk, final RevCommit headCommit) {
        LOG.info("Starting search at {}", headCommit);

        final RevCommit parent = getRevCommit(revWalk, headCommit.getParent(0).getId());
        LOG.info("Finding most recent maintainers file in {}", parent);

        final String parentIdName = parent.getId().getName();
        LOG.info("Parent id name {}", parentIdName);

        try (TreeWalk treeWalk = new TreeWalk(repository)) {
            treeWalk.addTree(parent.getTree());
            treeWalk.setRecursive(true);
            treeWalk.setFilter(PathFilter.create(maintainersFileName));
            LOG.info("Attempting to find {}", maintainersFileName);

            if (treeWalk.next()) {
                LOG.info("Maintainers file found in commit {}", parent.getId());
                ObjectId objectId = treeWalk.getObjectId(0);
                ObjectLoader loader = repository.open(objectId);

                // and then one can the loader to read the file
                final ByteArrayOutputStream out = new ByteArrayOutputStream();
                loader.copyTo(out);
                revWalk.dispose();
                return new String(out.toByteArray());
            }

            LOG.info("Maintainers file not found in commit {}, going deep", parent.getId());
            if (parent.getParents() == null) {
                throw new IllegalStateException(format("Root of branch reached with commit %s", parent));
            }
            return findMostRecentMaintainersChangeContent(maintainersFileName, repository, revWalk, parent);
        } catch (IOException e) {
            throw new IllegalStateException(format("Unable to detect maintainers file in %s", parent.getId()));
        }
    }

    private RevCommit getRevCommit(final RevWalk revWalk, final ObjectId id) {
        try {
            return revWalk.parseCommit(id);
        } catch (IOException e) {
            throw new IllegalStateException(format("Unable to parse commit %s", id));
        }
    }
}