<commit_before>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root.

package com.microsoft.alm.common.utils;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;

public class UrlHelper {
    private static final Logger logger = LoggerFactory.getLogger(UrlHelper.class);

    public static final String URL_SEPARATOR = "/";

    // this formatter assumes the entire text is a hyperlink, works for short messages
    public static final String SHORT_HTTP_LINK_FORMATTER = "<html><body><a href=\"%s\">%s</a></body></html>";

    public static final String HOST_VSO = "visualstudio.com";
    public static final String HOST_TFS_ALL_IN = "tfsallin.net"; //azure test subscriptions

    private static final String URL_GIT_PATH_SEGMENT = "_git";
    private static final String URL_OPTIMIZED_REF_PATH_SEGMENT = "_optimized";
    private static final String URL_FULL_REF_PATH_SEGMENT = "_full";

    private static final String HTTP_PROTOCOL = "http";
    private static final String HTTPS_PROTOCOL = "https";

    public static URI createUri(final String url) {
        return URI.create(getCmdLineFriendlyUrl(url));
    }

    public static boolean isValidUrl(final String serverUrl) {
        try {
            new URL(serverUrl);

            return true;
        } catch (MalformedURLException e) {
            //URL is not in a valid form
            logger.warn(serverUrl, e);
        }
        return false;
    }

    public static String asString(final URI uri) {
        if (uri != null) {
            return uri.toString();
        }

        return null;
    }

    public static String trimTrailingSeparators(final String uri) {
        if (StringUtils.isNotEmpty(uri)) {
            int lastIndex = uri.length();
            while (lastIndex > 0 && uri.charAt(lastIndex - 1) == URL_SEPARATOR.charAt(0)) {
                lastIndex--;
            }
            if (lastIndex >= 0) {
                return uri.substring(0, lastIndex);
            }
        }

        return uri;
    }

    public static boolean isVSO(final URI uri) {
        if (uri != null && uri.getHost() != null) {
            final String host = uri.getHost().toLowerCase();
            if (StringUtils.endsWith(host, HOST_VSO) || StringUtils.endsWith(host, HOST_TFS_ALL_IN)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isTeamServicesUrl(final String url) {
        if (StringUtils.containsIgnoreCase(url, HOST_VSO) || StringUtils.containsIgnoreCase(url, HOST_TFS_ALL_IN)) {
            return true;
        }
        return false;
    }

    public static boolean isGitRemoteUrl(final String gitRemoteUrl) {
        return StringUtils.contains(gitRemoteUrl, "/_git/");
    }

    public static boolean isSshGitRemoteUrl(final String gitRemoteUrl) {
        if (isGitRemoteUrl(gitRemoteUrl) && isTeamServicesUrl(gitRemoteUrl)) {
            if (StringUtils.startsWithIgnoreCase(gitRemoteUrl, "https://") ||
                    StringUtils.startsWithIgnoreCase(gitRemoteUrl, "http://")) {
                return false;
            }

            if (StringUtils.startsWithIgnoreCase(gitRemoteUrl, "ssh://")) {
                return true;
            }

            // check for @ in url - team project name, repo name, collection name and account name don't allow @
            // E.g of valid url formats:
            // ssh://account@account.visualstudio.com:22/Collection/_git/Repo
            // <EMAIL>:22/Collection/_git/Repo
            if (StringUtils.contains(gitRemoteUrl, "@")) {
                return true;
            }
        }
        return false;
    }

    public static String getHttpsGitUrlFromSshUrl(final String sshGitRemoteUrl) {

        if (isSshGitRemoteUrl(sshGitRemoteUrl)) {
            final URI sshUrl;
            if (!StringUtils.startsWithIgnoreCase(sshGitRemoteUrl, "ssh://")) {
                sshUrl = UrlHelper.createUri("ssh://" + sshGitRemoteUrl);
            } else {
                sshUrl = UrlHelper.createUri(sshGitRemoteUrl);
            }
            final String host = sshUrl.getHost();
            final String path = sshUrl.getPath();
            final URI httpsUrl = UrlHelper.createUri("https://" + host + path);
            return httpsUrl.toString();
        }

        return null;
    }

    public static String getCmdLineFriendlyUrl(final String url) {
        return StringUtils.replace(url, " ", "%20");
    }

    public static URI getVSOAccountURI(final String accountName) {
        return UrlHelper.createUri("https://" + accountName + "." + HOST_VSO); //TODO: how to get account url correctly?
    }

    public static URI getCollectionURI(final URI serverUri, final String collectionName) {
        if (isVSO(serverUri) && getVSOAccountURI(collectionName).equals(serverUri)) {
            //collection in the domain case on VSTS
            return serverUri;
        }
        return UrlHelper.createUri(serverUri.toString().concat(URL_SEPARATOR).concat(collectionName));
    }

    public static URI getTeamProjectURI(final URI serverUri, final String collectionName, final String teamProjectName) {
        return UrlHelper.createUri(getCollectionURI(serverUri, collectionName).toString().concat(URL_SEPARATOR).concat(teamProjectName));
    }

    public static URI getCreateWorkItemURI(final URI projectUri) {
        //TODO: this url isn't exactly correct because we don't know the WI Type to create
        return UrlHelper.createUri(projectUri.toString().concat(URL_SEPARATOR).concat("_workitems"));
    }

    public static URI getMyWorkItemsURI(final URI projectUri) {
        // The default query when you navigate to the work items section is the "Assigned to me" query results
        return UrlHelper.createUri(projectUri.toString().concat(URL_SEPARATOR).concat("_workitems"));
    }
<commit_msg>PR 96053: Adding link creation for specific work items<commit_after>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root.

package com.microsoft.alm.common.utils;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;

public class UrlHelper {
    private static final Logger logger = LoggerFactory.getLogger(UrlHelper.class);

    public static final String URL_SEPARATOR = "/";

    // this formatter assumes the entire text is a hyperlink, works for short messages
    public static final String SHORT_HTTP_LINK_FORMATTER = "<html><body><a href=\"%s\">%s</a></body></html>";

    public static final String HOST_VSO = "visualstudio.com";
    public static final String HOST_TFS_ALL_IN = "tfsallin.net"; //azure test subscriptions

    private static final String URL_GIT_PATH_SEGMENT = "_git";
    private static final String URL_WIT_PATH_SEGMENT = "_workitems";
    private static final String URL_OPTIMIZED_REF_PATH_SEGMENT = "_optimized";
    private static final String URL_FULL_REF_PATH_SEGMENT = "_full";
    private static final String URL_WIT_SPECIFIC_ITEM_PATH_SEGMENT = "?id=%d&_a=edit";

    private static final String HTTP_PROTOCOL = "http";
    private static final String HTTPS_PROTOCOL = "https";

    public static URI createUri(final String url) {
        return URI.create(getCmdLineFriendlyUrl(url));
    }

    public static boolean isValidUrl(final String serverUrl) {
        try {
            new URL(serverUrl);

            return true;
        } catch (MalformedURLException e) {
            //URL is not in a valid form
            logger.warn(serverUrl, e);
        }
        return false;
    }

    public static String asString(final URI uri) {
        if (uri != null) {
            return uri.toString();
        }

        return null;
    }

    public static String trimTrailingSeparators(final String uri) {
        if (StringUtils.isNotEmpty(uri)) {
            int lastIndex = uri.length();
            while (lastIndex > 0 && uri.charAt(lastIndex - 1) == URL_SEPARATOR.charAt(0)) {
                lastIndex--;
            }
            if (lastIndex >= 0) {
                return uri.substring(0, lastIndex);
            }
        }

        return uri;
    }

    public static boolean isVSO(final URI uri) {
        if (uri != null && uri.getHost() != null) {
            final String host = uri.getHost().toLowerCase();
            if (StringUtils.endsWith(host, HOST_VSO) || StringUtils.endsWith(host, HOST_TFS_ALL_IN)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isTeamServicesUrl(final String url) {
        if (StringUtils.containsIgnoreCase(url, HOST_VSO) || StringUtils.containsIgnoreCase(url, HOST_TFS_ALL_IN)) {
            return true;
        }
        return false;
    }

    public static boolean isGitRemoteUrl(final String gitRemoteUrl) {
        return StringUtils.contains(gitRemoteUrl, "/_git/");
    }

    public static boolean isSshGitRemoteUrl(final String gitRemoteUrl) {
        if (isGitRemoteUrl(gitRemoteUrl) && isTeamServicesUrl(gitRemoteUrl)) {
            if (StringUtils.startsWithIgnoreCase(gitRemoteUrl, "https://") ||
                    StringUtils.startsWithIgnoreCase(gitRemoteUrl, "http://")) {
                return false;
            }

            if (StringUtils.startsWithIgnoreCase(gitRemoteUrl, "ssh://")) {
                return true;
            }

            // check for @ in url - team project name, repo name, collection name and account name don't allow @
            // E.g of valid url formats:
            // ssh://account@account.visualstudio.com:22/Collection/_git/Repo
            // <EMAIL>:22/Collection/_git/Repo
            if (StringUtils.contains(gitRemoteUrl, "@")) {
                return true;
            }
        }
        return false;
    }

    public static String getHttpsGitUrlFromSshUrl(final String sshGitRemoteUrl) {

        if (isSshGitRemoteUrl(sshGitRemoteUrl)) {
            final URI sshUrl;
            if (!StringUtils.startsWithIgnoreCase(sshGitRemoteUrl, "ssh://")) {
                sshUrl = UrlHelper.createUri("ssh://" + sshGitRemoteUrl);
            } else {
                sshUrl = UrlHelper.createUri(sshGitRemoteUrl);
            }
            final String host = sshUrl.getHost();
            final String path = sshUrl.getPath();
            final URI httpsUrl = UrlHelper.createUri("https://" + host + path);
            return httpsUrl.toString();
        }

        return null;
    }

    public static String getCmdLineFriendlyUrl(final String url) {
        return StringUtils.replace(url, " ", "%20");
    }

    public static URI getVSOAccountURI(final String accountName) {
        return UrlHelper.createUri("https://" + accountName + "." + HOST_VSO); //TODO: how to get account url correctly?
    }

    public static URI getCollectionURI(final URI serverUri, final String collectionName) {
        if (isVSO(serverUri) && getVSOAccountURI(collectionName).equals(serverUri)) {
            //collection in the domain case on VSTS
            return serverUri;
        }
        return UrlHelper.createUri(serverUri.toString().concat(URL_SEPARATOR).concat(collectionName));
    }

    public static URI getTeamProjectURI(final URI serverUri, final String collectionName, final String teamProjectName) {
        return UrlHelper.createUri(getCollectionURI(serverUri, collectionName).toString().concat(URL_SEPARATOR).concat(teamProjectName));
    }

    public static URI getCreateWorkItemURI(final URI projectUri) {
        //TODO: this url isn't exactly correct because we don't know the WI Type to create
        return UrlHelper.createUri(projectUri.toString().concat(URL_SEPARATOR).concat(URL_WIT_PATH_SEGMENT));
    }

    public static URI getSpecificWorkItemURI(final URI projectUri, final int workItemId) {
        return UrlHelper.createUri(projectUri.toString().concat(URL_SEPARATOR).concat(URL_WIT_PATH_SEGMENT).concat(String.format(URL_WIT_SPECIFIC_ITEM_PATH_SEGMENT, workItemId)));
    }

    public static URI getMyWorkItemsURI(final URI projectUri) {
        // The default query when you navigate to the work items section is the "Assigned to me" query results
        return UrlHelper.createUri(projectUri.toString().concat(URL_SEPARATOR).concat(URL_WIT_PATH_SEGMENT));
    }

{'fraction_non_alphanumeric': 0.0967381768881091, 'fraction_numerical': 0.0024722864662253766, 'mean_word_length': 2.5972461273666094, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '10952', 'n_tokens_mistral': 3602, 'n_tokens_neox': 3457, 'n_words': 896}