com.hazelcast.qasonar.utils.GitHubUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.hazelcast.qasonar.utils.GitHubUtils.java

Source

/*
 * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
 *
 * 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.hazelcast.qasonar.utils;

import org.kohsuke.github.GHContent;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHMilestone;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHPullRequestFileDetail;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;

import static com.hazelcast.qasonar.utils.DebugUtils.debug;
import static com.hazelcast.qasonar.utils.DebugUtils.isDebug;
import static com.hazelcast.qasonar.utils.TimeTracker.record;
import static com.hazelcast.qasonar.utils.Utils.sleepMillis;
import static org.apache.commons.io.IOUtils.copy;
import static org.kohsuke.github.GHIssueState.CLOSED;
import static org.kohsuke.github.GHIssueState.OPEN;

public final class GitHubUtils {

    static final GHMilestone MERGED_MILESTONE = new GHMilestone();
    static final GHMilestone ALL_MILESTONE = new GHMilestone();
    static final GHMilestone NO_MILESTONE = new GHMilestone();

    private static final int GITHUB_FILE_DOWNLOAD_RETRIES = 10;
    private static final int GITHUB_EXCEPTION_DELAY_MILLIS = 200;
    private static final int GITHUB_EXCEPTION_LOG_FREQUENCY = 10;

    private static final String MERGED_MILESTONE_TITLE = "MERGED";
    private static final String ALL_MILESTONE_TITLE = "ALL";
    private static final String NO_MILESTONE_TITLE = "NONE";

    private static final AtomicInteger EXCEPTION_COUNTER = new AtomicInteger();

    private GitHubUtils() {
    }

    public static GHRepository getGitHubRepository(PropertyReader propertyReader) {
        return (GHRepository) execute(TimeTrackerLabel.GET_GITHUB_REPOSITORY, () -> {
            GitHub github = GitHub.connect();
            return github.getRepository(propertyReader.getGitHubRepository());
        });
    }

    public static String getFileContentsFromGitHub(GHRepository repo, String fileName) throws IOException {
        long started = System.nanoTime();
        try {
            IOException exception = null;
            for (int i = 0; i < GITHUB_FILE_DOWNLOAD_RETRIES; i++) {
                try {
                    GHContent fileContent = repo.getFileContent(fileName);

                    StringWriter writer = new StringWriter();
                    copy(fileContent.read(), writer);

                    return writer.toString();
                } catch (FileNotFoundException e) {
                    throw e;
                } catch (IOException e) {
                    exception = e;
                }
                sleepMillis(GITHUB_EXCEPTION_DELAY_MILLIS * (i + 1));
            }
            throw exception;
        } finally {
            record(TimeTrackerLabel.GET_FILE_CONTENTS_FROM_GITHUB, System.nanoTime() - started);
        }
    }

    public static String getAuthor(GHRepository repo, int gitPullRequest) {
        return (String) execute(TimeTrackerLabel.GET_AUTHOR, () -> {
            GHUser user = repo.getIssue(gitPullRequest).getUser();
            String author = user.getName();
            if (author != null) {
                return author;
            }
            return user.getLogin();
        });
    }

    public static GHMilestone getMilestone(String milestoneTitle, GHRepository repo) {
        return (GHMilestone) execute(TimeTrackerLabel.GET_MILESTONE, () -> {
            switch (milestoneTitle) {
            case MERGED_MILESTONE_TITLE:
                return MERGED_MILESTONE;
            case ALL_MILESTONE_TITLE:
                return ALL_MILESTONE;
            case NO_MILESTONE_TITLE:
                return NO_MILESTONE;
            default:
                for (GHMilestone milestoneEntry : repo.listMilestones(OPEN)) {
                    if (milestoneTitle.equals(milestoneEntry.getTitle())) {
                        return milestoneEntry;
                    }
                }
                for (GHMilestone milestoneEntry : repo.listMilestones(CLOSED)) {
                    if (milestoneTitle.equals(milestoneEntry.getTitle())) {
                        return milestoneEntry;
                    }
                }
                return null;
            }
        });
    }

    public static GHPullRequest getPullRequest(GHRepository repo, int gitPullRequest) {
        return (GHPullRequest) execute(TimeTrackerLabel.GET_PULL_REQUEST,
                () -> repo.getPullRequest(gitPullRequest));
    }

    @SuppressWarnings("unchecked")
    public static List<Integer> getPullRequests(GHRepository repo, GHMilestone milestone, Calendar calendar) {
        return (List<Integer>) execute(TimeTrackerLabel.GET_PULL_REQUESTS, () -> {
            List<Integer> pullRequests = new ArrayList<>();

            for (GHPullRequest pullRequest : repo.getPullRequests(CLOSED)) {
                if (!matchesMilestone(pullRequest, milestone)) {
                    continue;
                }
                if (isDebug()) {
                    printDebugOutput(calendar, pullRequest);
                } else {
                    System.out.print('.');
                }
                pullRequests.add(pullRequest.getNumber());
            }
            if (!isDebug()) {
                System.out.println();
            }
            return pullRequests;
        });
    }

    public static boolean isMerged(GHPullRequest pullRequest) {
        return (boolean) execute(TimeTrackerLabel.IS_MERGED, pullRequest::isMerged);
    }

    public static boolean isClosed(GHPullRequest pullRequest) {
        return (boolean) execute(TimeTrackerLabel.IS_CLOSED,
                () -> pullRequest.getState().equals(GHIssueState.CLOSED));
    }

    @SuppressWarnings("unchecked")
    public static List<GHPullRequestFileDetail> getPullRequestFiles(GHPullRequest pullRequest) {
        return (List<GHPullRequestFileDetail>) execute(TimeTrackerLabel.GET_PULL_REQUEST_FILES, () -> {
            List<GHPullRequestFileDetail> files = new ArrayList<>();
            for (GHPullRequestFileDetail pullRequestFile : pullRequest.listFiles()) {
                files.add(pullRequestFile);
            }
            return files;
        });
    }

    static boolean matchesMilestone(GHPullRequest pullRequest, GHMilestone milestone) {
        if (milestone == MERGED_MILESTONE) {
            // we don't care if the PR has a milestone at all
            return isMerged(pullRequest);
        }
        GHMilestone prMilestone = pullRequest.getMilestone();
        if (milestone == ALL_MILESTONE) {
            // we don't care which milestone the PR has
            return (prMilestone != null && isMerged(pullRequest));
        }
        if (milestone == NO_MILESTONE) {
            // the PR should not have a milestone
            return (prMilestone == null && isMerged(pullRequest));
        }
        // the PR has to have the wanted milestone
        return (prMilestone != null && prMilestone.getId() == milestone.getId() && isMerged(pullRequest));
    }

    private static void printDebugOutput(Calendar calendar, GHPullRequest pullRequest) {
        calendar.setTime(pullRequest.getClosedAt());
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        debug("[%d-%02d-%02d] #%04d %s", year, month, day, pullRequest.getNumber(), pullRequest.getTitle());
    }

    private static Object execute(TimeTrackerLabel label, Callable callable) {
        long started = System.nanoTime();
        try {
            while (true) {
                try {
                    return callable.call();
                } catch (Throwable t) {
                    int counter = EXCEPTION_COUNTER.incrementAndGet();
                    if (counter % GITHUB_EXCEPTION_LOG_FREQUENCY == 0) {
                        counter = 0;
                        EXCEPTION_COUNTER.set(0);
                        t.printStackTrace();
                    }
                    sleepMillis(GITHUB_EXCEPTION_DELAY_MILLIS * counter);
                }
            }
        } finally {
            record(label, System.nanoTime() - started);
        }
    }
}