From f8163a05bef8a44a1e4633039bad01c4bfd79219 Mon Sep 17 00:00:00 2001 From: Glen Nicol Date: Wed, 20 Nov 2019 15:19:09 -0800 Subject: [PATCH] Feature: GitWeb Source Link provider GitWeb only currently supports SSH repository URLs. https://github.com/dotnet/sourcelink/pull/505 --- SourceLink.sln | 12 ++ src/Common/CommonResources.resx | 6 + src/Common/TranslateRepositoryUrlGitTask.cs | 71 ++++++++-- src/Common/xlf/CommonResources.cs.xlf | 10 ++ src/Common/xlf/CommonResources.de.xlf | 10 ++ src/Common/xlf/CommonResources.es.xlf | 10 ++ src/Common/xlf/CommonResources.fr.xlf | 26 ++-- src/Common/xlf/CommonResources.it.xlf | 10 ++ src/Common/xlf/CommonResources.ja.xlf | 10 ++ src/Common/xlf/CommonResources.ko.xlf | 10 ++ src/Common/xlf/CommonResources.pl.xlf | 10 ++ src/Common/xlf/CommonResources.pt-BR.xlf | 10 ++ src/Common/xlf/CommonResources.ru.xlf | 26 ++-- src/Common/xlf/CommonResources.tr.xlf | 10 ++ src/Common/xlf/CommonResources.zh-Hans.xlf | 10 ++ src/Common/xlf/CommonResources.zh-Hant.xlf | 10 ++ .../GitWebTests.cs | 130 ++++++++++++++++++ .../GetSourceLinkUrlTests.cs | 58 ++++++++ ...crosoft.SourceLink.GitWeb.UnitTests.csproj | 9 ++ .../TranslateRepositoryUrlsTests.cs | 51 +++++++ src/SourceLink.GitWeb/GetSourceLinkUrl.cs | 37 +++++ .../Microsoft.SourceLink.GitWeb.csproj | 33 +++++ .../Microsoft.SourceLink.GitWeb.nuspec | 17 +++ .../TranslateRepositoryUrls.cs | 33 +++++ .../build/Microsoft.SourceLink.GitWeb.targets | 65 +++++++++ .../Microsoft.SourceLink.GitWeb.targets | 4 + src/SourceLink.GitWeb/xlf/Resources.cs.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.de.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.es.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.fr.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.it.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.ja.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.ko.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.pl.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.ru.xlf | 32 +++++ src/SourceLink.GitWeb/xlf/Resources.tr.xlf | 32 +++++ .../xlf/Resources.zh-Hans.xlf | 32 +++++ .../xlf/Resources.zh-Hant.xlf | 32 +++++ 39 files changed, 1075 insertions(+), 29 deletions(-) create mode 100644 src/SourceLink.Git.IntegrationTests/GitWebTests.cs create mode 100644 src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs create mode 100644 src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj create mode 100644 src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs create mode 100644 src/SourceLink.GitWeb/GetSourceLinkUrl.cs create mode 100644 src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj create mode 100644 src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec create mode 100644 src/SourceLink.GitWeb/TranslateRepositoryUrls.cs create mode 100644 src/SourceLink.GitWeb/build/Microsoft.SourceLink.GitWeb.targets create mode 100644 src/SourceLink.GitWeb/buildMultiTargeting/Microsoft.SourceLink.GitWeb.targets create mode 100644 src/SourceLink.GitWeb/xlf/Resources.cs.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.de.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.es.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.fr.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.it.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.ja.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.ko.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.pl.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.ru.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.tr.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf create mode 100644 src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf diff --git a/SourceLink.sln b/SourceLink.sln index 49098d14..b185660e 100644 --- a/SourceLink.sln +++ b/SourceLink.sln @@ -54,6 +54,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.AzureD EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.AzureDevOpsServer.Git.UnitTests", "src\SourceLink.AzureDevOpsServer.Git.UnitTests\Microsoft.SourceLink.AzureDevOpsServer.Git.UnitTests.csproj", "{79371F26-FB84-408D-A4A1-B142B247C288}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.GitWeb", "src\SourceLink.GitWeb\Microsoft.SourceLink.GitWeb.csproj", "{C78DD3EF-9D20-4E00-8237-E871BB53F840}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SourceLink.GitWeb.UnitTests", "src\SourceLink.GitWeb.UnitTests\Microsoft.SourceLink.GitWeb.UnitTests.csproj", "{50503A43-08C0-493B-B8CC-F368983644C1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -136,6 +140,14 @@ Global {79371F26-FB84-408D-A4A1-B142B247C288}.Debug|Any CPU.Build.0 = Debug|Any CPU {79371F26-FB84-408D-A4A1-B142B247C288}.Release|Any CPU.ActiveCfg = Release|Any CPU {79371F26-FB84-408D-A4A1-B142B247C288}.Release|Any CPU.Build.0 = Release|Any CPU + {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C78DD3EF-9D20-4E00-8237-E871BB53F840}.Release|Any CPU.Build.0 = Release|Any CPU + {50503A43-08C0-493B-B8CC-F368983644C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50503A43-08C0-493B-B8CC-F368983644C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50503A43-08C0-493B-B8CC-F368983644C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50503A43-08C0-493B-B8CC-F368983644C1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Common/CommonResources.resx b/src/Common/CommonResources.resx index 876d8353..5329649d 100644 --- a/src/Common/CommonResources.resx +++ b/src/Common/CommonResources.resx @@ -141,4 +141,10 @@ Unable to determine repository url, the source code won't be available via source link. + + The provided url '{0}' is not a complete URI + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + \ No newline at end of file diff --git a/src/Common/TranslateRepositoryUrlGitTask.cs b/src/Common/TranslateRepositoryUrlGitTask.cs index b87b2d70..56cbccd9 100644 --- a/src/Common/TranslateRepositoryUrlGitTask.cs +++ b/src/Common/TranslateRepositoryUrlGitTask.cs @@ -33,6 +33,9 @@ public class TranslateRepositoryUrlsGitTask : Task protected virtual string? TranslateHttpUrl(Uri uri) => uri.GetScheme() + "://" + uri.GetAuthority() + uri.GetPathAndQuery(); + protected virtual bool IsProtocolSupportedByProvider(string protocol) + => true; + public override bool Execute() { ExecuteImpl(); @@ -47,26 +50,45 @@ private void ExecuteImpl() return; } + static bool getUri(string? url, out Uri uri) => Uri.TryCreate(url, UriKind.Absolute, out uri); + static bool isMatchingHostUri(Uri hostUri, Uri uri) - => uri.GetHost().Equals(hostUri.GetHost(), StringComparison.OrdinalIgnoreCase) || + => uri.GetHost().Equals(hostUri.GetHost(), StringComparison.OrdinalIgnoreCase) || uri.GetHost().EndsWith("." + hostUri.GetHost(), StringComparison.OrdinalIgnoreCase); // only need to translate valid ssh URLs that match one of our hosts: - string? translate(string? url) + string translate(Uri uri) { - if (Uri.TryCreate(url, UriKind.Absolute, out var uri) && - hostUris.Any(h => isMatchingHostUri(h, uri))) + if(hostUris.Any(h => isMatchingHostUri(h, uri))) { return (uri.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase) ? TranslateHttpUrl(uri) : uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? TranslateHttpUrl(uri) : uri.Scheme.Equals("ssh", StringComparison.OrdinalIgnoreCase) ? TranslateSshUrl(uri) : - uri.Scheme.Equals("git", StringComparison.OrdinalIgnoreCase) ? TranslateGitUrl(uri) : null) ?? url; + uri.Scheme.Equals("git", StringComparison.OrdinalIgnoreCase) ? TranslateGitUrl(uri) : null) ?? uri.OriginalString; } - return url; + return uri.OriginalString; + } + + var providerName = this.GetType().Namespace; + if(getUri(RepositoryUrl, out var repoUrlUri)) + { + if(!IsProtocolSupportedByProvider(repoUrlUri.Scheme)) + { + // TODO should this be an error or a warning? + Log.LogError(CommonResources.RepositoryUrlIsNotSupportedByProvider, providerName, repoUrlUri.Scheme); + return; + } + + TranslatedRepositoryUrl = translate(repoUrlUri); + } + else + { + // preserve previous behavior of using the URL as is if URI cannot be parsed. + TranslatedRepositoryUrl = RepositoryUrl; + Log.LogWarning(CommonResources.RepositoryUrlIsNotComplete, RepositoryUrl); } - TranslatedRepositoryUrl = translate(RepositoryUrl); TranslatedSourceRoots = SourceRoots; if (TranslatedSourceRoots != null) @@ -78,12 +100,35 @@ static bool isMatchingHostUri(Uri hostUri, Uri uri) continue; } - // Item metadata are stored msbuild-escaped. GetMetadata unescapes, SetMetadata stores the value as specified. - // When initializing the URL metadata from git information we msbuild-escaped the URL to preserve any URL escapes in it. - // Here, GetMetadata unescapes the msbuild escapes, then we translate the URL and finally msbuild-escape - // the resulting URL to preserve any URL escapes. - sourceRoot.SetMetadata(Names.SourceRoot.ScmRepositoryUrl, - Evaluation.ProjectCollection.Escape(translate(sourceRoot.GetMetadata(Names.SourceRoot.ScmRepositoryUrl)))); + var scmRepoUrl = sourceRoot.GetMetadata(Names.SourceRoot.ScmRepositoryUrl); + if (getUri(scmRepoUrl, out var scmRepoUri)) + { + if (!IsProtocolSupportedByProvider(scmRepoUri.Scheme)) + { + // TODO should this be an error or a warning? + Log.LogError(CommonResources.RepositoryUrlIsNotSupportedByProvider, providerName, scmRepoUri.Scheme); + continue; + } + + setScmRepoUrlMetaData(translate(scmRepoUri)); + } + else + { + // preserve previous behavior of using the URL as is if URI cannot be parsed. + Log.LogWarning(CommonResources.RepositoryUrlIsNotComplete, scmRepoUrl); + setScmRepoUrlMetaData(scmRepoUrl); + } + + void setScmRepoUrlMetaData(string url) + { + // Item metadata are stored msbuild-escaped. GetMetadata unescapes, SetMetadata + // stores the value as specified. When initializing the URL metadata from git + // information we msbuild-escaped the URL to preserve any URL escapes in it. + // Here, GetMetadata unescapes the msbuild escapes, then we translate the URL + // and finally msbuild-escape the resulting URL to preserve any URL escapes. + sourceRoot.SetMetadata(Names.SourceRoot.ScmRepositoryUrl, + Evaluation.ProjectCollection.Escape(url)); + } } } } diff --git a/src/Common/xlf/CommonResources.cs.xlf b/src/Common/xlf/CommonResources.cs.xlf index f1ebb8b0..95269ffb 100644 --- a/src/Common/xlf/CommonResources.cs.xlf +++ b/src/Common/xlf/CommonResources.cs.xlf @@ -12,6 +12,16 @@ Položka {0} ve skupině položek {1} musí uvádět metadata {2}. + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. Nejde určit adresu URL úložiště. Zdrojový kód nebude k dispozici přes zdrojový odkaz. diff --git a/src/Common/xlf/CommonResources.de.xlf b/src/Common/xlf/CommonResources.de.xlf index e58ec006..7a9bc620 100644 --- a/src/Common/xlf/CommonResources.de.xlf +++ b/src/Common/xlf/CommonResources.de.xlf @@ -12,6 +12,16 @@ Das Element "{0}" der Elementgruppe "{1}" muss die Metadaten "{2}" angeben. + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. Die URL für das Repository konnte nicht ermittelt werden. Daher ist der Quellcode nicht über den Link zur Quelle verfügbar. diff --git a/src/Common/xlf/CommonResources.es.xlf b/src/Common/xlf/CommonResources.es.xlf index 6c77c859..2419fc7d 100644 --- a/src/Common/xlf/CommonResources.es.xlf +++ b/src/Common/xlf/CommonResources.es.xlf @@ -12,6 +12,16 @@ El elemento "{0}" del grupo de elementos "{1}" debe especificar los metadatos "{2}" + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. No se puede determinar la URL del repositorio, el código fuente no estará disponible a través del vínculo de origen. diff --git a/src/Common/xlf/CommonResources.fr.xlf b/src/Common/xlf/CommonResources.fr.xlf index ffb60259..7b541b50 100644 --- a/src/Common/xlf/CommonResources.fr.xlf +++ b/src/Common/xlf/CommonResources.fr.xlf @@ -4,42 +4,52 @@ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. - Le groupe d'éléments {0} est vide. Au moins un hôte de dépôt {1} est nécessaire pour générer SourceLink. + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. Item '{0}' of item group '{1}' must specify metadata '{2}' - L'élément '{0}' du groupe d'éléments '{1}' doit spécifier les métadonnées '{2}' + Item '{0}' of item group '{1}' must specify metadata '{2}' + + + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. Unable to determine repository url, the source code won't be available via source link. - Impossible de déterminer l'URL du dépôt, le code source n'est pas disponible via le lien source. + Unable to determine repository url, the source code won't be available via source link. The value of {0} with identity '{1}' is invalid: '{2}' - La valeur de {0} avec l'identité '{1}' n’est pas valide : '{2}' + The value of {0} with identity '{1}' is invalid: '{2}' The value of {0} with identity '{1}' is not a valid commit hash: '{2}' - La valeur de {0} avec l'identité '{1}' n'est pas un hachage de validation valide : '{2}' + The value of {0} with identity '{1}' is not a valid commit hash: '{2}' The value passed to task parameter {0} is not a valid domain name: '{1}' - La valeur passée au paramètre de tâche {0} n'est pas un nom de domaine valide : '{1}' + The value passed to task parameter {0} is not a valid domain name: '{1}' The value passed to task parameter {0} is not a valid host URI: '{1}' - La valeur passée au paramètre de tâche {0} n'est pas un URI d'hôte valide : '{1}' + The value passed to task parameter {0} is not a valid host URI: '{1}' The value passed to task parameter {0} is not a valid URI: '{1}' - La valeur passée au paramètre de tâche {0} n'est pas un URI valide : '{1}' + The value passed to task parameter {0} is not a valid URI: '{1}' diff --git a/src/Common/xlf/CommonResources.it.xlf b/src/Common/xlf/CommonResources.it.xlf index 222ef236..3531c844 100644 --- a/src/Common/xlf/CommonResources.it.xlf +++ b/src/Common/xlf/CommonResources.it.xlf @@ -12,6 +12,16 @@ L'elemento '{0}' del gruppo di elementi '{1}' deve specificare i metadati '{2}' + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. Non è possibile determinare l'URL del repository. Il codice sorgente non sarà disponibile tramite il collegamento all'origine. diff --git a/src/Common/xlf/CommonResources.ja.xlf b/src/Common/xlf/CommonResources.ja.xlf index 9457924d..69dc8e7b 100644 --- a/src/Common/xlf/CommonResources.ja.xlf +++ b/src/Common/xlf/CommonResources.ja.xlf @@ -12,6 +12,16 @@ 項目グループ '{1}' の項目 '{0}' には、メタデータ '{2}' を指定する必要があります + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. リポジトリのURLを特定できません。ソース リンクを使用してソース コードを利用できません。 diff --git a/src/Common/xlf/CommonResources.ko.xlf b/src/Common/xlf/CommonResources.ko.xlf index 178cd0af..2328edc7 100644 --- a/src/Common/xlf/CommonResources.ko.xlf +++ b/src/Common/xlf/CommonResources.ko.xlf @@ -12,6 +12,16 @@ 항목 그룹 '{1}'의 '{0}' 항목은 '{2}' 메타데이터를 지정해야 합니다. + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. 리포지토리 URL을 확인할 수 없으며, 소스 링크를 통해 소스 코드를 사용할 수 없습니다. diff --git a/src/Common/xlf/CommonResources.pl.xlf b/src/Common/xlf/CommonResources.pl.xlf index e3021dcf..33550ba8 100644 --- a/src/Common/xlf/CommonResources.pl.xlf +++ b/src/Common/xlf/CommonResources.pl.xlf @@ -12,6 +12,16 @@ Element „{0}” grupy elementów „{1}” musi określać metadane „{2}”. + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. Nie można określić adresu URL repozytorium, kod źródłowy nie będzie dostępny za pośrednictwem linku do źródła. diff --git a/src/Common/xlf/CommonResources.pt-BR.xlf b/src/Common/xlf/CommonResources.pt-BR.xlf index d289ee2c..bb0d4e68 100644 --- a/src/Common/xlf/CommonResources.pt-BR.xlf +++ b/src/Common/xlf/CommonResources.pt-BR.xlf @@ -12,6 +12,16 @@ Item '{0}' do grupo de item '{1}' deve especificar metadados '{2}' + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. Não é possível determinar a URL do repositório, o código-fonte não estará disponível através do link de origem. diff --git a/src/Common/xlf/CommonResources.ru.xlf b/src/Common/xlf/CommonResources.ru.xlf index 290c9079..9856bab9 100644 --- a/src/Common/xlf/CommonResources.ru.xlf +++ b/src/Common/xlf/CommonResources.ru.xlf @@ -4,42 +4,52 @@ {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. - Группа элементов {0} пуста. Для создания SourceLink нужно указать хотя бы один хост репозитория {1}. + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. Item '{0}' of item group '{1}' must specify metadata '{2}' - Необходимо указать метаданные '{2}' для элемента '{0}' в группе элементов '{1}' + Item '{0}' of item group '{1}' must specify metadata '{2}' + + + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. Unable to determine repository url, the source code won't be available via source link. - Не удается определить URL-адрес репозитория, исходный код не будут доступен по ссылке. + Unable to determine repository url, the source code won't be available via source link. The value of {0} with identity '{1}' is invalid: '{2}' - Значение {0} с идентификатором '{1}' является недопустимым: '{2}' + The value of {0} with identity '{1}' is invalid: '{2}' The value of {0} with identity '{1}' is not a valid commit hash: '{2}' - Значение {0} с идентификатором '{1}' не является допустимым хэшем фиксации: '{2}' + The value of {0} with identity '{1}' is not a valid commit hash: '{2}' The value passed to task parameter {0} is not a valid domain name: '{1}' - Значение, передаваемое параметру задачи {0}, не является допустимым доменным именем: "{1}" + The value passed to task parameter {0} is not a valid domain name: '{1}' The value passed to task parameter {0} is not a valid host URI: '{1}' - Значение, передаваемое параметру задачи {0}, не является допустимым URI узла: "{1}" + The value passed to task parameter {0} is not a valid host URI: '{1}' The value passed to task parameter {0} is not a valid URI: '{1}' - Значение, переданное в качестве параметра задачи {0}, не является допустимым URI: '{1}' + The value passed to task parameter {0} is not a valid URI: '{1}' diff --git a/src/Common/xlf/CommonResources.tr.xlf b/src/Common/xlf/CommonResources.tr.xlf index 89a36224..cf7c12f5 100644 --- a/src/Common/xlf/CommonResources.tr.xlf +++ b/src/Common/xlf/CommonResources.tr.xlf @@ -12,6 +12,16 @@ '{1}' öğe grubunun '{0}' öğesi, '{2}' meta verilerini belirtmelidir + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. Depo URL'si belirlenemiyor. Kaynak kod, kaynak bağlantısı aracılığıyla kullanılamayacak. diff --git a/src/Common/xlf/CommonResources.zh-Hans.xlf b/src/Common/xlf/CommonResources.zh-Hans.xlf index 74dc1582..19e12968 100644 --- a/src/Common/xlf/CommonResources.zh-Hans.xlf +++ b/src/Common/xlf/CommonResources.zh-Hans.xlf @@ -12,6 +12,16 @@ 项组 "{1}" 的项 "{0}" 必须指定元数据 "{2}" + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. 无法确定存储库 URL,源代码将无法通过源链接获得。 diff --git a/src/Common/xlf/CommonResources.zh-Hant.xlf b/src/Common/xlf/CommonResources.zh-Hant.xlf index 623c7110..03fadbf4 100644 --- a/src/Common/xlf/CommonResources.zh-Hant.xlf +++ b/src/Common/xlf/CommonResources.zh-Hant.xlf @@ -12,6 +12,16 @@ 項目群組 '{1}' 的項目 '{0}' 必須指定中繼資料 '{2}' + + The provided url '{0}' is not a complete URI + The provided url '{0}' is not a complete URI + + + + The {0} provider does not support translating the '{1}' protocol to content URLs. + The {0} provider does not support translating the '{1}' protocol to content URLs. + + Unable to determine repository url, the source code won't be available via source link. 無法判斷存放庫 URL,無法透過原始連結取得原始程式碼。 diff --git a/src/SourceLink.Git.IntegrationTests/GitWebTests.cs b/src/SourceLink.Git.IntegrationTests/GitWebTests.cs new file mode 100644 index 00000000..5b60d7cd --- /dev/null +++ b/src/SourceLink.Git.IntegrationTests/GitWebTests.cs @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See +// License.txt in the project root for license information. + +using System; +using System.IO; +using TestUtilities; + +namespace Microsoft.SourceLink.IntegrationTests +{ + public class GitWebTests : DotNetSdkTestBase + { + public GitWebTests() + : base("Microsoft.SourceLink.GitWeb") + { + } + + [ConditionalFact(typeof(DotNetSdkAvailable))] + public void FullValidation_Ssh() + { + // Test non-ascii characters and escapes in the URL. Escaped URI reserved characters + // should remain escaped, non-reserved characters unescaped in the results. + var repoUrl = $"ssh://git@噸.com/test-%72epo\u1234%24%2572%2F.git"; + var repoName = "test-repo\u1234%24%2572%2F.git"; + + var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName }, repoUrl); + var commitSha = repo.Head.Tip.Sha; + + VerifyValues( + customProps: @" + + true + + + + +", + customTargets: "", + targets: new[] + { + "Build", "Pack" + }, + expressions: new[] + { + "@(SourceRoot)", + "@(SourceRoot->'%(SourceLinkUrl)')", + "$(SourceLink)", + "$(PrivateRepositoryUrl)", + "$(RepositoryUrl)" + }, + expectedResults: new[] + { + ProjectSourceRoot, + $"https://噸.com/gitweb/?p={repoName};a=blob_plain;hb={commitSha};f=*", + s_relativeSourceLinkJsonPath, + $"ssh://git@噸.com/{repoName}", + $"ssh://git@噸.com/{repoName}" + }); + + AssertEx.AreEqual( + $@"{{""documents"":{{""{ProjectSourceRoot.Replace(@"\", @"\\")}*"":""https://噸.com/gitweb/?p={repoName};a=blob_plain;hb={commitSha};f=*""}}}}", + File.ReadAllText(Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath))); + + TestUtilities.ValidateAssemblyInformationalVersion( + Path.Combine(ProjectDir.Path, s_relativeOutputFilePath), + "1.0.0+" + commitSha); + + TestUtilities.ValidateNuSpecRepository( + Path.Combine(ProjectDir.Path, s_relativePackagePath), + type: "git", + commit: commitSha, + url: $"ssh://git@噸.com/{repoName}"); + } + + [ConditionalFact(typeof(DotNetSdkAvailable))] + public void Issues_error_on_git_url() + { + var repoUrl = "git://噸.com/invalid_url_protocol.git"; + var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName }, repoUrl); + var commitSha = repo.Head.Tip.Sha; + + VerifyValues( + customProps: @" + + true + + + + +", + customTargets: "", + targets: new[] + { + "Build", "Pack" + }, + expressions: Array.Empty(), + expectedErrors: new[]{ + "The Microsoft.SourceLink.GitWeb provider does not support translating the 'git' protocol to content URLs." + }); + } + + [ConditionalFact(typeof(DotNetSdkAvailable))] + public void Issues_error_on_https_url() + { + var repoUrl = "https://噸.com/invalid_url_protocol.git"; + var repo = GitUtilities.CreateGitRepositoryWithSingleCommit(ProjectDir.Path, new[] { ProjectFileName }, repoUrl); + var commitSha = repo.Head.Tip.Sha; + + VerifyValues( + customProps: @" + + true + + + + +", + customTargets: "", + targets: new[] + { + "Build", "Pack" + }, + expressions: Array.Empty(), + expectedErrors: new[] + { + // TODO how to reference resource? + "The Microsoft.SourceLink.GitWeb provider does not support translating the 'https' protocol to content URLs." + }); + } + } +} diff --git a/src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs b/src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs new file mode 100644 index 00000000..82da152f --- /dev/null +++ b/src/SourceLink.GitWeb.UnitTests/GetSourceLinkUrlTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See +// License.txt in the project root for license information. +using Microsoft.Build.Tasks.SourceControl; +using TestUtilities; +using Xunit; +using static TestUtilities.KeyValuePairUtils; + +namespace Microsoft.SourceLink.GitWeb.UnitTests +{ + public class GetSourceLinkUrlTests + { + [Fact] + public void EmptyHosts() + { + var engine = new MockEngine(); + + var task = new GetSourceLinkUrl() + { + BuildEngine = engine, + SourceRoot = new MockItem("x", KVP("RepositoryUrl", "http://abc.com"), KVP("SourceControl", "git")), + }; + + bool result = task.Execute(); + + AssertEx.AssertEqualToleratingWhitespaceDifferences( + "ERROR : " + string.Format(CommonResources.AtLeastOneRepositoryHostIsRequired, "SourceLinkGitWebHost", "GitWeb"), engine.Log); + + Assert.False(result); + } + + [Theory] + [InlineData("", "")] + [InlineData("", "/")] + [InlineData("/", "")] + [InlineData("/", "/")] + public void BuildSourceLinkUrl(string s1, string s2) + { + var engine = new MockEngine(); + + var task = new GetSourceLinkUrl() + { + BuildEngine = engine, + SourceRoot = new MockItem("/src/", KVP("RepositoryUrl", "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git" + s1), KVP("SourceControl", "git"), KVP("RevisionId", "0123456789abcdefABCDEF000000000000000000")), + Hosts = new[] + { + // NOTE: i don't know what the spec parameter is for. but for all the other + // tests like this for various providers it is the domain of the Repo URL. + new MockItem("src.intranet.company.com", KVP("ContentUrl", "https://src.intranet.company.com/gitweb" + s2)), + } + }; + + bool result = task.Execute(); + AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log); + AssertEx.AreEqual("https://src.intranet.company.com/gitweb/?p=root_dir_name/sub_dirs/reponame.git;a=blob_plain;hb=0123456789abcdefABCDEF000000000000000000;f=*", task.SourceLinkUrl); + Assert.True(result); + } + } +} diff --git a/src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj b/src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj new file mode 100644 index 00000000..16608152 --- /dev/null +++ b/src/SourceLink.GitWeb.UnitTests/Microsoft.SourceLink.GitWeb.UnitTests.csproj @@ -0,0 +1,9 @@ + + + net461;netcoreapp2.0 + + + + + + diff --git a/src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs b/src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs new file mode 100644 index 00000000..255fdb2f --- /dev/null +++ b/src/SourceLink.GitWeb.UnitTests/TranslateRepositoryUrlsTests.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See +// License.txt in the project root for license information. +using System.Linq; +using TestUtilities; +using Xunit; +using static TestUtilities.KeyValuePairUtils; + +namespace Microsoft.SourceLink.GitWeb.UnitTests +{ + public class TranslateRepositoryUrlsTests + { + [Fact] + public void Translate() + { + var engine = new MockEngine(); + + var task = new TranslateRepositoryUrls() + { + BuildEngine = engine, + RepositoryUrl = "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git", + IsSingleProvider = true, + SourceRoots = new[] + { + new MockItem("/1/", KVP("SourceControl", "git"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git")), + new MockItem("/2/", KVP("SourceControl", "tfvc"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git")), + new MockItem("/2/", KVP("SourceControl", "git"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git")), + new MockItem("/2/", KVP("SourceControl", "tfvc"), KVP("ScmRepositoryUrl", "ssh://git@src.intranet.company2.com/root_dir_name/sub_dirs/reponame.git")), + }, + Hosts = new[] + { + new MockItem("src.intranet.company1.com") + } + }; + + bool result = task.Execute(); + AssertEx.AssertEqualToleratingWhitespaceDifferences("", engine.Log); + + AssertEx.AreEqual("ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git", task.TranslatedRepositoryUrl); + + AssertEx.Equal(new[] + { + "ssh://git@src.intranet.company.com/root_dir_name/sub_dirs/reponame.git", + "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git", + "ssh://git@src.intranet.company1.com/root_dir_name/sub_dirs/reponame.git", + "ssh://git@src.intranet.company2.com/root_dir_name/sub_dirs/reponame.git", + }, task.TranslatedSourceRoots.Select(r => r.GetMetadata("ScmRepositoryUrl"))); + + Assert.True(result); + } + } +} diff --git a/src/SourceLink.GitWeb/GetSourceLinkUrl.cs b/src/SourceLink.GitWeb/GetSourceLinkUrl.cs new file mode 100644 index 00000000..da5df319 --- /dev/null +++ b/src/SourceLink.GitWeb/GetSourceLinkUrl.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See +// License.txt in the project root for license information. + +using System; +using Microsoft.Build.Framework; +using Microsoft.Build.Tasks.SourceControl; + +namespace Microsoft.SourceLink.GitWeb +{ + /// + /// The task calculates SourceLink URL for a given SourceRoot. If the SourceRoot is associated + /// with a git repository with a recognized domain the output + /// property is set to the content URL corresponding to the domain, otherwise it is set to + /// string "N/A". + /// + public sealed class GetSourceLinkUrl : GetSourceLinkUrlGitTask + { + protected override string HostsItemGroupName => "SourceLinkGitWebHost"; + protected override string ProviderDisplayName => "GitWeb"; + + protected override Uri GetDefaultContentUriFromHostUri(string authority, Uri gitUri) + => new Uri($"https://{authority}/gitweb", UriKind.Absolute); + + protected override string BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem? hostItem) + { + var trimLeadingSlash = relativeUrl.TrimStart('/'); + var trimmedContentUrl = contentUri.ToString().TrimEnd('/', '\\'); + + // p = project/path + // a = action + // hb = SHA/revision + // f = repo file path + var gitwebRawUrl = UriUtilities.Combine(trimmedContentUrl, $"?p={trimLeadingSlash}.git;a=blob_plain;hb={revisionId};f=*"); + return gitwebRawUrl; + } + } +} diff --git a/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj new file mode 100644 index 00000000..fea0b608 --- /dev/null +++ b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.csproj @@ -0,0 +1,33 @@ + + + net461;netcoreapp2.0 + true + + + true + $(MSBuildProjectName).nuspec + $(OutputPath) + + Generates source link for Git repositories using a GitWeb server. + MSBuild Tasks GitWeb source link + true + + + + + + + + + Microsoft.Build.Tasks.SourceControl + true + + + + + + + + + + diff --git a/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec new file mode 100644 index 00000000..5acaea90 --- /dev/null +++ b/src/SourceLink.GitWeb/Microsoft.SourceLink.GitWeb.nuspec @@ -0,0 +1,17 @@ + + + + $CommonMetadataElements$ + + + + + + + $CommonFileElements$ + + + + + + diff --git a/src/SourceLink.GitWeb/TranslateRepositoryUrls.cs b/src/SourceLink.GitWeb/TranslateRepositoryUrls.cs new file mode 100644 index 00000000..69080d23 --- /dev/null +++ b/src/SourceLink.GitWeb/TranslateRepositoryUrls.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See +// License.txt in the project root for license information. + +using Microsoft.Build.Tasks.SourceControl; +using System; + +namespace Microsoft.SourceLink.GitWeb +{ + /// + /// This task normally translates all protocols to HTTPS git repo URLs for consistency. Not all + /// GitWebs support HTTPS URLs for clones. So instead we keep the SSH URL. The + /// Task converts the URLs to HTTP content URLs which GitWeb does + /// support. The output of this Task is independent of . + /// + public sealed class TranslateRepositoryUrls : TranslateRepositoryUrlsGitTask + { + protected override bool IsProtocolSupportedByProvider(string protocol) => string.Equals(protocol, "ssh", StringComparison.Ordinal); + + /// + /// Keep the SSH URL. It is the only protocol currently known to work with GitWeb. + /// + /// + /// as a string + protected override string TranslateSshUrl(Uri uri) + => uri.ToString(); + + protected override string TranslateGitUrl(Uri uri) + => throw new NotSupportedException("Git URLs are not supported by Microsoft.SourceLink.GitWeb."); + + protected override string TranslateHttpUrl(Uri uri) + => throw new NotSupportedException("HTTP URLs are not supported by Microsoft.SourceLink.GitWeb."); + } +} diff --git a/src/SourceLink.GitWeb/build/Microsoft.SourceLink.GitWeb.targets b/src/SourceLink.GitWeb/build/Microsoft.SourceLink.GitWeb.targets new file mode 100644 index 00000000..d5019e7a --- /dev/null +++ b/src/SourceLink.GitWeb/build/Microsoft.SourceLink.GitWeb.targets @@ -0,0 +1,65 @@ + + + + <_SourceLinkGitWebAssemblyFile Condition="'$(MSBuildRuntimeType)' != 'Core'">$(MSBuildThisFileDirectory)..\tools\net461\Microsoft.SourceLink.GitWeb.dll + <_SourceLinkGitWebAssemblyFile Condition="'$(MSBuildRuntimeType)' == 'Core'">$(MSBuildThisFileDirectory)..\tools\netcoreapp2.0\Microsoft.SourceLink.GitWeb.dll + + + + + + + $(SourceLinkUrlInitializerTargets);_InitializeGitWebSourceLinkUrl + $(SourceControlManagerUrlTranslationTargets);TranslateGitWebUrlsInSourceControlInformation + + + + + + + + + + + + + + + + + + + <_TranslatedSourceRoot Remove="@(_TranslatedSourceRoot)" /> + + + + + + + + + + + + + diff --git a/src/SourceLink.GitWeb/buildMultiTargeting/Microsoft.SourceLink.GitWeb.targets b/src/SourceLink.GitWeb/buildMultiTargeting/Microsoft.SourceLink.GitWeb.targets new file mode 100644 index 00000000..84afbc37 --- /dev/null +++ b/src/SourceLink.GitWeb/buildMultiTargeting/Microsoft.SourceLink.GitWeb.targets @@ -0,0 +1,4 @@ + + + + diff --git a/src/SourceLink.GitWeb/xlf/Resources.cs.xlf b/src/SourceLink.GitWeb/xlf/Resources.cs.xlf new file mode 100644 index 00000000..0e6540e3 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.cs.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + Skupina položek {0} je prázdná. Kvůli generování zdrojového odkazu se vyžaduje alespoň jeden hostitel úložiště {1}. + + + + {0} specifies an invalid URL: '{1}' + {0} určuje neplatnou adresu URL: {1}. + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + Hodnota {0} s identitou {1} je neplatná: {2}" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + Hodnota {0} s identitou {1} není platná hodnota hash potvrzení: {2}" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + Hodnota předaná parametru úlohy {0} není platný název hostitele: {1}. + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.de.xlf b/src/SourceLink.GitWeb/xlf/Resources.de.xlf new file mode 100644 index 00000000..dcc9a38f --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.de.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + Die Elementgruppe "{0}" ist leer. Mindestens ein {1}-Repositoryhost wird benötigt, um SourceLink zu generieren. + + + + {0} specifies an invalid URL: '{1}' + "{0}" gibt eine ungültige URL an: {1} + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + Der Wert von "{0}" mit der Identität "{1}" ist ungültig: "{2}" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + Der Wert von "{0}" mit der Identität "{1}" ist kein gültiger Commithash: "{2}" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + Der an den Taskparameter "{0}" übergebene Wert ist kein gültiger Hostname: "{1}" + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.es.xlf b/src/SourceLink.GitWeb/xlf/Resources.es.xlf new file mode 100644 index 00000000..17b78f7c --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.es.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + El grupo de elementos {0} está vacío. Se requiere al menos un repositorio {1} a fin de generar SourceLink. + + + + {0} specifies an invalid URL: '{1}' + {0} especifica una dirección URL no válida: "{1}" + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + El valor de {0} con identidad '{1}' no es válido '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + El valor de {0} con identidad '{1}' no es un hash de confirmación válido '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + El valor pasado al parámetro de tarea {0} no es un nombre de host válido: "{1}" + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.fr.xlf b/src/SourceLink.GitWeb/xlf/Resources.fr.xlf new file mode 100644 index 00000000..21751341 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.fr.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + Le groupe d'éléments {0} est vide. Au moins un hôte de dépôt {1} est nécessaire pour générer SourceLink. + + + + {0} specifies an invalid URL: '{1}' + {0} spécifie une URL non valide : '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + La valeur de {0} avec l'identité '{1}' n'est pas valide : '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + La valeur de {0} avec l'identité '{1}' n'est pas un hachage de validation valide : '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + La valeur passée au paramètre de tâche {0} n'est pas un nom d'hôte valide : '{1}' + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.it.xlf b/src/SourceLink.GitWeb/xlf/Resources.it.xlf new file mode 100644 index 00000000..f6f3cb05 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.it.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + Il gruppo di elementi {0} è vuoto. Per generare SourceLink, è necessario almeno un host di repository di {1}. + + + + {0} specifies an invalid URL: '{1}' + {0} specifica un URL non valido: '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + Il valore di {0} con identità '{1}' non è valido: '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + Il valore di {0} con identità '{1}' non è un hash commit valido: '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + Il valore passato al parametro {0} dell'attività non è un nome host valido: '{1}' + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.ja.xlf b/src/SourceLink.GitWeb/xlf/Resources.ja.xlf new file mode 100644 index 00000000..98145efd --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.ja.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + {0} 項目グループが空です。SourceLink を生成するには、少なくとも 1 つの {1} リポジトリ ホストが必要です。 + + + + {0} specifies an invalid URL: '{1}' + {0} は無効な URL を指定しています: '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + ID '{1}' の {0} の値は無効です: '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + ID '{1}' の {0} の値は有効なコミット ハッシュではありません: '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + タスク パラメーター {0} に渡された値は有効なホスト名ではありません: '{1}' + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.ko.xlf b/src/SourceLink.GitWeb/xlf/Resources.ko.xlf new file mode 100644 index 00000000..ce5571ba --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.ko.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + {0} 항목 그룹이 비어 있습니다. SourceLink를 생성하려면 {1} 리포지토리 호스트가 하나 이상 필요합니다. + + + + {0} specifies an invalid URL: '{1}' + {0}이(가) 잘못된 URL을 지정합니다. '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + ID가 '{1}'인 {0}의 값이 잘못되었습니다. '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + ID가 '{1}'인 {0}의 값이 유효한 커밋 해시가 아닙니다. '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + 작업 매개 변수 {0}에 전달되는 값이 유효한 호스트 이름이 아닙니다. '{1}' + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.pl.xlf b/src/SourceLink.GitWeb/xlf/Resources.pl.xlf new file mode 100644 index 00000000..5f2e9268 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.pl.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + Grupa elementów {0} jest pusta. Wymagany jest co najmniej jeden host repozytorium {1} w celu wygenerowania elementu SourceLink. + + + + {0} specifies an invalid URL: '{1}' + Element {0} określa nieprawidłowy adres URL: „{1}” + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + Wartość elementu {0} z tożsamością „{1}” jest nieprawidłowa: „{2}”" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + Wartość elementu {0} z tożsamością „{1}” nie jest prawidłowym skrótem zatwierdzenia: „{2}”" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + Wartość przekazana do parametru zadania {0} nie jest prawidłową nazwą hosta: „{1}” + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf b/src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf new file mode 100644 index 00000000..4a461578 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.pt-BR.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + O grupo de itens {0} está vazio. Pelo menos um host de repositório {1} é necessário para gerar o SourceLink. + + + + {0} specifies an invalid URL: '{1}' + {0} especifica uma URL inválida: '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + O valor de {0} com a identidade '{1}' é inválido: '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + O valor de {0} com a identidade '{1}' não é um hash de confirmação válido: '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + O valor passado para o parâmetro de tarefa {0} não é um nome de host válido: '{1}' + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.ru.xlf b/src/SourceLink.GitWeb/xlf/Resources.ru.xlf new file mode 100644 index 00000000..8683b5a7 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.ru.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + Группа элементов {0} пуста. Для создания SourceLink нужно указать хотя бы один хост репозитория {1}. + + + + {0} specifies an invalid URL: '{1}' + В {0} указан недопустимый URL-адрес: "{1}" + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + Значение {0} с идентификатором "{1}" недопустимо: "{2}" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + Значение {0} с идентификатором "{1}" не является допустимым хэш-кодом фиксации: "{2}" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + Значение, передаваемое параметру задачи {0}, не является допустимым именем узла: "{1}" + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.tr.xlf b/src/SourceLink.GitWeb/xlf/Resources.tr.xlf new file mode 100644 index 00000000..cb9305b8 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.tr.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + {0} öğe grubu boş. SourceLink oluşturmak için en az bir {1} depo konağı gereklidir. + + + + {0} specifies an invalid URL: '{1}' + {0} geçersiz bir URL belirtiyor: '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + '{1}' kimliğine sahip {0} değeri geçersiz: '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + '{1}' kimliğine sahip {0} değeri geçerli bir işleme karması değil: '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + {0} görev parametresine geçirilen değer geçerli bir konak adı değil: '{1}' + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf b/src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf new file mode 100644 index 00000000..e4a4010d --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.zh-Hans.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + {0} 项目组为空。至少需要一个 {1} 存储库主机才能生成 SourceLink。 + + + + {0} specifies an invalid URL: '{1}' + {0} 指定无效的 URL:“{1}” + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + 带有 '{1}' 标识的 {0} 的值无效: '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + 带有 '{1}' 标识的 {0} 的值不是有效的提交哈希: '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + 传递给任务参数 {0} 的值不是有效的主机名:“{1}” + + + + + \ No newline at end of file diff --git a/src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf b/src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf new file mode 100644 index 00000000..ab6c29b8 --- /dev/null +++ b/src/SourceLink.GitWeb/xlf/Resources.zh-Hant.xlf @@ -0,0 +1,32 @@ + + + + + + {0} item group is empty. At least one {1} repository host is required in order to generate SourceLink. + {0} 項目群組是空的。至少需要一個 {1} 存放庫主機,才可產生 SourceLink。 + + + + {0} specifies an invalid URL: '{1}' + {0} 指定的 URL 無效: '{1}' + + + + The value of {0} with identity '{1}' is invalid: '{2}'" + 識別為 {1} 之 {0} 的值無效: '{2}'" + + + + The value of {0} with identity '{1}' is not a valid commit hash: '{2}'" + 識別為 {1} 之 {0} 的值不是有效的認可雜湊: '{2}'" + + + + The value passed to task parameter {0} is not a valid host name: '{1}' + 傳遞給工作參數 {0} 的值並非有效的主機名稱: '{1}' + + + + + \ No newline at end of file