All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jenkins.updatebot.commands.StatusInfo Maven / Gradle / Ivy

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright 2016 Red Hat, Inc.
 *
 * Red Hat licenses this file to you 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.jenkins.updatebot.commands;

import io.jenkins.updatebot.Configuration;
import io.jenkins.updatebot.repository.LocalRepository;
import io.jenkins.updatebot.support.Strings;
import io.fabric8.utils.Objects;
import org.fusesource.jansi.Ansi;
import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * Represents the status of a repository
 */
public class StatusInfo {
    private static final transient Logger LOG = LoggerFactory.getLogger(StatusInfo.class);

    private final LocalRepository repository;
    private final Status status;
    private final GHIssue issue;
    private final GHPullRequest pullRequest;
    private final String cloneUrl;
    private final GHIssueState issueState;
    private final GHIssueState pullRequestState;
    private String issueUrl;
    private String pullRequestUrl;

    public StatusInfo(LocalRepository repository, Status status, GHIssue issue, GHPullRequest pullRequest) {
        this.repository = repository;
        this.issue = issue;
        this.pullRequest = pullRequest;
        this.issueUrl = (issue != null) ? Strings.toString(issue.getHtmlUrl()) : null;
        this.pullRequestUrl = (pullRequest != null) ? Strings.toString(pullRequest.getHtmlUrl()) : null;
        this.cloneUrl = repository.getCloneUrl();
        this.issueState = state(issue);
        this.pullRequestState = state(pullRequest);
        if (nullOrClosed(issueState) && nullOrClosed(pullRequestState) && status.equals(Status.PENDING)) {
            status = Status.COMPLETE;
        }
        this.status = status;
    }

    /**
     * Returns true if there are any pending statuses in the map
     */
    public static boolean isPending(Map statusMap) {
        return isPending(statusMap.values());
    }

    /**
     * Returns true if there are any pending statuses in the map
     */
    public static boolean isPending(Iterable statuses) {
        for (StatusInfo status : statuses) {
            if (status.isPending()) {
                return true;
            }
        }
        return false;
    }

    protected static boolean nullOrClosed(GHIssueState state) {
        return state == null || state.equals(GHIssueState.CLOSED);
    }

    protected static GHIssueState state(GHIssue issue) {
        if (issue != null) {
            return issue.getState();
        }
        return null;
    }

    /**
     * Lets return the current status by combining the old and new status maps to handle new maps
     * not including links to old pending issues or pull requests that are now closed
     */
    public static Map changedStatuses(Configuration configuration, Map oldMap, Map newMap) {
        Set allKeys = new LinkedHashSet(oldMap.keySet());
        allKeys.addAll(newMap.keySet());
        Map answer = new LinkedHashMap<>();
        for (String key : allKeys) {
            StatusInfo status = changedStatus(configuration, oldMap.get(key), newMap.get(key));
            if (status != null) {
                answer.put(key, status);
            }
        }
        return answer;
    }

    private static StatusInfo changedStatus(Configuration configuration, StatusInfo oldStatus, StatusInfo newStatus) {
        if (oldStatus == null) {
            return newStatus;
        } else {
            if (newStatus == null) {
                return null;
            }
            if (oldStatus.equalStatus(newStatus)) {
                return null;
            }
            LOG.info("Status changed for " + oldStatus + " " + newStatus);
            // lets use the status which has the issue/pull request which is usually the old one
            // as when things close they don't appear in searches for open issues/PRs
            if (newStatus.getIssueUrl() != null || newStatus.getPullRequestUrl() != null) {
                LOG.info("new status has PR " + newStatus);
                return newStatus;
            } else {
                return StatusInfo.createStatus(configuration, oldStatus);
            }
        }
    }

    private static StatusInfo createStatus(Configuration configuration, StatusInfo oldStatus) {
        GHRepository repository = null;
        GHIssue issue = oldStatus.getIssue();
        if (issue != null) {
            repository = issue.getRepository();
            try {
                issue = repository.getIssue(issue.getNumber());
            } catch (IOException e) {
                configuration.warn(LOG, "Failed to lookup issue " + oldStatus.getIssueUrl() + ". " + e, e);
            }
        }
        GHPullRequest pullRequest = oldStatus.getPullRequest();
        if (pullRequest != null) {
            if (repository == null) {
                repository = pullRequest.getRepository();
            }
            try {
                pullRequest = repository.getPullRequest(pullRequest.getNumber());
            } catch (IOException e) {
                configuration.warn(LOG, "Failed to lookup pull request " + oldStatus.getPullRequestUrl() + ". " + e, e);
            }
        }
        return new StatusInfo(oldStatus.getRepository(), oldStatus.getStatus(), issue, pullRequest);
    }

    @Override
    public String toString() {
        return "StatusInfo{" +
                "name='" + getFullName() + '\'' +
                ", status=" + status +
                ", issueState=" + issueState +
                ", pullRequestState=" + pullRequestState +
                ", pullRequestUrl='" + pullRequestUrl + '\'' +
                '}';
    }

    /**
     * Returns true if this and that object have the same underlying status
     */
    public boolean equalStatus(StatusInfo that) {
        return Objects.equal(this.status, that.status) &&
                Objects.equal(this.issueState, that.issueState) &&
                Objects.equal(this.pullRequestState, that.pullRequestState);
    }


    /**
     * Returns true if this status is pending
     */
    public boolean isPending() {
        return status.equals(Status.PENDING);
    }

    public LocalRepository getRepository() {
        return repository;
    }

    public Status getStatus() {
        return status;
    }

    public GHIssue getIssue() {
        return issue;
    }

    public GHPullRequest getPullRequest() {
        return pullRequest;
    }

    public String getFullName() {
        return getRepository().getFullName();
    }

    public String getCloneUrl() {
        return cloneUrl;
    }

    public String getIssueUrl() {
        return issueUrl;
    }

    public String getPullRequestUrl() {
        return pullRequestUrl;
    }

    public GHIssueState getIssueState() {
        return issueState;
    }

    public GHIssueState getPullRequestState() {
        return pullRequestState;
    }

    /**
     * Returns a description of the status
     *
     * @param configuration
     */
    public String description(Configuration configuration) {
        StringBuilder builder = new StringBuilder();
        Ansi.Color color = Configuration.COLOR_PENDING;
        if (status != null) {
            switch (status) {
                case COMPLETE:
                    color = Configuration.COLOR_COMPLETE;
                    break;
                case FAILED:
                    color = Configuration.COLOR_WARNING;
                    break;
            }
            builder.append(status.getName());
            builder.append(":");
        }
        if (issueUrl != null) {
            builder.append(" issue ");
            if (issueState != null) {
                builder.append(format(issueState));
                builder.append(" ");
            }
            builder.append(issueUrl);
        }
        if (pullRequestUrl != null) {
            builder.append(" pull request ");
            if (pullRequestState != null) {
                builder.append(format(pullRequestState));
                builder.append(" ");
            }
            builder.append(pullRequestUrl);
        }
        // lets add a trailing space just in case ansi color codes break URLs in logs ;)
        builder.append(" ");
        return configuration.colored(color, builder.toString());
    }

    protected String format(GHIssueState state) {
        if (state != null) {
            return state.toString().toLowerCase();
        }
        return null;
    }

    public void logStatus(Logger log) {
        // TODO

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy