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

com.github.robozonky.app.version.GithubMetadataParser Maven / Gradle / Ivy

/*
 * Copyright 2021 The RoboZonky 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.github.robozonky.app.version;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.json.bind.JsonbBuilder;

import org.apache.commons.lang3.reflect.TypeUtils;

import com.github.robozonky.internal.Defaults;
import com.github.robozonky.internal.util.StringUtil;
import com.github.robozonky.internal.util.UrlUtil;
import com.github.robozonky.internal.util.functional.Either;

/**
 * Retrieve latest released version from Github API.
 */
final class GithubMetadataParser implements Function> {

    private final String server;

    GithubMetadataParser(final String server) {
        this.server = Objects.requireNonNull(server);
    }

    GithubMetadataParser() {
        this("https://api.github.com");
    }

    private static List retrieveReleases(final InputStream json) {
        ParameterizedType releaseListType = TypeUtils.parameterize(List.class, GithubRelease.class);
        try (var jsonb = JsonbBuilder.create()) {
            return ((List) jsonb.fromJson(json, releaseListType))
                .stream()
                .collect(Collectors.toUnmodifiableList());
        } catch (final Exception ex) {
            throw new IllegalStateException(ex);
        }
    }

    private static List jsonToVersionStrings(final String source) {
        var inputStream = new ByteArrayInputStream(source.getBytes(Defaults.CHARSET));
        return retrieveReleases(inputStream);
    }

    private static Response processVersion(final String currentVersion, final List knownVersions) {
        // Assumes release name in the Maven version format.
        // ("RoboZonky X.Y.Z", possibly with a suffix of "-beta-W", "-cr-W" etc.)
        var knownVersionName = "RoboZonky " + currentVersion;
        // Assumes that versions are sorted in the decreasing order of recency.
        var newerReleases = knownVersions.stream()
            .takeWhile(release -> !Objects.equals(release.getName(), knownVersionName))
            .collect(Collectors.toUnmodifiableList());
        var latestRelease = newerReleases.stream()
            .filter(f -> !f.isDraft())
            .filter(f -> !f.isPrerelease())
            .findFirst();
        var latestExperimentalRelease = newerReleases.stream()
            .filter(f -> !f.isDraft())
            .filter(GithubRelease::isPrerelease)
            .findFirst();

        // At this point, we know that latestRelease is more recent than current, if exists.
        // latestExperimentalRelease is more recent than current, if exists.
        return latestExperimentalRelease.map(experimentalRelease -> latestRelease.map(release -> {
            if (experimentalRelease.getDatePublished()
                .isAfter(release.getDatePublished())) {
                return Response.moreRecent(release, experimentalRelease);
            } else {
                return Response.moreRecentStable(release);
            }
        })
            .orElseGet(() -> Response.moreRecentExperimental(experimentalRelease)))
            .orElseGet(() -> latestRelease.map(Response::moreRecentStable)
                .orElseGet(Response::noMoreRecentVersion));
    }

    private static InputStream getGithubData(String server) throws IOException {
        var url = server + "/repos/robozonky/robozonky/releases";
        return UrlUtil.open(new URL(url))
            .getInputStream();
    }

    private Either> getAvailableVersions() {
        try (var inputStream = getGithubData(server)) {
            return Either.right(jsonToVersionStrings(StringUtil.toString(inputStream)));
        } catch (Exception ex) {
            return Either.left(ex);
        }
    }

    @Override
    public Either apply(final String currentVersion) {
        if (currentVersion == null || Objects.equals(currentVersion, "unknown") || currentVersion.isEmpty() ||
                currentVersion.contains("SNAPSHOT")) {
            return Either.right(Response.noMoreRecentVersion());
        }
        return getAvailableVersions()
            .fold(Either::left, r -> Either.right(processVersion(currentVersion, r)));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy