Merge branch 'master' into fix-code-coverage

This commit is contained in:
Stanley Goldman 2018-09-25 08:13:49 -04:00 коммит произвёл GitHub
Родитель ddf7e1071a 6e1b392a09
Коммит 7693b475a5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 144 добавлений и 33 удалений

Просмотреть файл

@ -121,7 +121,20 @@ namespace GitHub.Services
try
{
await vsGitServices.Clone(cloneUrl, repositoryPath, true, progress);
await usageTracker.IncrementCounter(x => x.NumberOfClones);
var repositoryUrl = new UriString(cloneUrl).ToRepositoryUrl();
var isDotCom = HostAddress.IsGitHubDotComUri(repositoryUrl);
if (isDotCom)
{
await usageTracker.IncrementCounter(x => x.NumberOfGitHubClones);
}
else
{
// If it isn't a GitHub URL, assume it's an Enterprise URL
await usageTracker.IncrementCounter(x => x.NumberOfEnterpriseClones);
}
}
catch (Exception ex)
{

Просмотреть файл

@ -23,6 +23,8 @@ namespace GitHub.ViewModels.Dialog.Clone
readonly IOperatingSystem os;
readonly IConnectionManager connectionManager;
readonly IRepositoryCloneService service;
readonly IUsageService usageService;
readonly IUsageTracker usageTracker;
readonly IReadOnlyList<IRepositoryCloneTabViewModel> tabs;
string path;
IRepositoryModel previousRepository;
@ -34,6 +36,8 @@ namespace GitHub.ViewModels.Dialog.Clone
IOperatingSystem os,
IConnectionManager connectionManager,
IRepositoryCloneService service,
IUsageService usageService,
IUsageTracker usageTracker,
IRepositorySelectViewModel gitHubTab,
IRepositorySelectViewModel enterpriseTab,
IRepositoryUrlViewModel urlTab)
@ -41,6 +45,8 @@ namespace GitHub.ViewModels.Dialog.Clone
this.os = os;
this.connectionManager = connectionManager;
this.service = service;
this.usageService = usageService;
this.usageTracker = usageTracker;
GitHubTab = gitHubTab;
EnterpriseTab = enterpriseTab;
@ -119,6 +125,33 @@ namespace GitHub.ViewModels.Dialog.Clone
}
this.WhenAnyValue(x => x.SelectedTabIndex).Subscribe(x => tabs[x].Activate().Forget());
// Users in group A will see the URL tab by default
if (await IsGroupA().ConfigureAwait(false))
{
SelectedTabIndex = 2;
}
switch (SelectedTabIndex)
{
case 0:
usageTracker.IncrementCounter(model => model.NumberOfCloneViewGitHubTab).Forget();
break;
case 1:
usageTracker.IncrementCounter(model => model.NumberOfCloneViewEnterpriseTab).Forget();
break;
case 2:
usageTracker.IncrementCounter(model => model.NumberOfCloneViewUrlTab).Forget();
break;
}
}
// Put 50% of users in group A
async Task<bool> IsGroupA()
{
var userGuid = await usageService.GetUserGuid().ConfigureAwait(false);
var lastByte = userGuid.ToByteArray().Last();
return lastByte % 2 == 0;
}
void BrowseForDirectory()

Просмотреть файл

@ -86,6 +86,11 @@ namespace GitHub.Models
public int ExecuteToggleInlineCommentMarginCommand { get; set; }
public int NumberOfPullRequestFileMarginToggleInlineCommentMargin { get; set; }
public int NumberOfPullRequestFileMarginViewChanges { get; set; }
public int NumberOfCloneViewGitHubTab { get; set; }
public int NumberOfCloneViewEnterpriseTab { get; set; }
public int NumberOfCloneViewUrlTab { get; set; }
public int NumberOfGitHubClones { get; set; }
public int NumberOfEnterpriseClones { get; set; }
}
}
}

Просмотреть файл

@ -2,7 +2,7 @@
<xliff xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="zh-CN" original="../GitHub.VisualStudio.vsct">
<body>
<trans-unit id="addConnectionCommand|ButtonText">
<trans-unit id="addConnectionCommand|ButtonText" approved="yes">
<source>&amp;Connect to GitHub</source>
<target xml:lang="zh-CN" state="translated">连接至GitHub(&amp;C)</target>
<note/>
@ -12,7 +12,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.ConnectToGitHub</target>
<note/>
</trans-unit>
<trans-unit id="backCommand|ButtonText">
<trans-unit id="backCommand|ButtonText" approved="yes">
<source>Back</source>
<target xml:lang="zh-CN" state="translated">返回</target>
<note/>
@ -22,7 +22,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.Back</target>
<note/>
</trans-unit>
<trans-unit id="copyLinkCommand|ButtonText">
<trans-unit id="copyLinkCommand|ButtonText" approved="yes">
<source>Copy link to clipboard</source>
<target xml:lang="zh-CN" state="translated">复制连结到剪贴簿</target>
<note/>
@ -32,7 +32,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.CopyLink</target>
<note/>
</trans-unit>
<trans-unit id="forwardCommand|ButtonText">
<trans-unit id="forwardCommand|ButtonText" approved="yes">
<source>Forward</source>
<target xml:lang="zh-CN" state="translated">转发</target>
<note/>
@ -42,9 +42,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.Forward</target>
<note/>
</trans-unit>
<trans-unit id="githubCommand|ButtonText">
<trans-unit id="githubCommand|ButtonText" approved="yes">
<source>View on GitHub</source>
<target xml:lang="zh-CN" state="needs-translation">View on GitHub</target>
<target xml:lang="zh-CN" state="translated">在GitHub上打开</target>
<note/>
</trans-unit>
<trans-unit id="githubCommand|LocCanonicalName">
@ -52,9 +52,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.ViewOnGitHub</target>
<note/>
</trans-unit>
<trans-unit id="goToSolutionOrPullRequestFileCommand|ButtonText">
<trans-unit id="goToSolutionOrPullRequestFileCommand|ButtonText" approved="yes">
<source>Go To Solution/PR File</source>
<target xml:lang="zh-CN" state="needs-translation">Go To Solution/PR File</target>
<target xml:lang="zh-CN" state="translated">转到解决方案/PR文件</target>
<note/>
</trans-unit>
<trans-unit id="goToSolutionOrPullRequestFileCommand|LocCanonicalName">
@ -62,7 +62,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.GoToSolutionOrPRFile</target>
<note/>
</trans-unit>
<trans-unit id="helpCommand|ButtonText">
<trans-unit id="helpCommand|ButtonText" approved="yes">
<source>Help</source>
<target xml:lang="zh-CN" state="translated">帮助</target>
<note/>
@ -72,9 +72,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.Help</target>
<note/>
</trans-unit>
<trans-unit id="idBlameCommand|ButtonText">
<trans-unit id="idBlameCommand|ButtonText" approved="yes">
<source>Blame</source>
<target xml:lang="zh-CN" state="needs-translation">Blame</target>
<target xml:lang="zh-CN" state="translated">追溯</target>
<note/>
</trans-unit>
<trans-unit id="idBlameCommand|LocCanonicalName">
@ -82,7 +82,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.Blame</target>
<note/>
</trans-unit>
<trans-unit id="idCreateGistCommand|ButtonText">
<trans-unit id="idCreateGistCommand|ButtonText" approved="yes">
<source>Create a GitHub Gist</source>
<target xml:lang="zh-CN" state="translated">创建一个GitHub Gist</target>
<note/>
@ -92,9 +92,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.CreateGist</target>
<note/>
</trans-unit>
<trans-unit id="idCreateGistEnterpriseCommand|ButtonText">
<trans-unit id="idCreateGistEnterpriseCommand|ButtonText" approved="yes">
<source>Create an Enterprise Gist</source>
<target xml:lang="zh-CN" state="needs-translation">Create an Enterprise Gist</target>
<target xml:lang="zh-CN" state="translated">创建企业Gist</target>
<note/>
</trans-unit>
<trans-unit id="idCreateGistEnterpriseCommand|LocCanonicalName">
@ -104,12 +104,12 @@
</trans-unit>
<trans-unit id="idGitHubContextMenu|ButtonText">
<source>GitHub</source>
<target xml:lang="zh-CN" state="translated">GitHub</target>
<target xml:lang="zh-CN" state="needs-translation">GitHub</target>
<note/>
</trans-unit>
<trans-unit id="idGitHubContextMenu|CommandName">
<source>GitHub</source>
<target xml:lang="zh-CN" state="translated">GitHub</target>
<target xml:lang="zh-CN" state="needs-translation">GitHub</target>
<note/>
</trans-unit>
<trans-unit id="idGitHubToolbar|ButtonText">
@ -122,9 +122,9 @@
<target xml:lang="zh-CN" state="needs-translation">Window Toolbar</target>
<note/>
</trans-unit>
<trans-unit id="openFromClipboardCommand|ButtonText">
<trans-unit id="openFromClipboardCommand|ButtonText" approved="yes">
<source>Open from clipboard</source>
<target xml:lang="zh-CN" state="needs-translation">Open from clipboard</target>
<target xml:lang="zh-CN" state="translated">从剪贴板打开</target>
<note/>
</trans-unit>
<trans-unit id="openFromClipboardCommand|LocCanonicalName">
@ -132,9 +132,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.OpenFromClipboard</target>
<note/>
</trans-unit>
<trans-unit id="openFromUrlCommand|ButtonText">
<trans-unit id="openFromUrlCommand|ButtonText" approved="yes">
<source>Open from GitHub...</source>
<target xml:lang="zh-CN" state="needs-translation">Open from GitHub...</target>
<target xml:lang="zh-CN" state="translated">从 GitHub 打开...</target>
<note/>
</trans-unit>
<trans-unit id="openFromUrlCommand|LocCanonicalName">
@ -142,9 +142,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.OpenFromUrl</target>
<note/>
</trans-unit>
<trans-unit id="openLinkCommand|ButtonText">
<trans-unit id="openLinkCommand|ButtonText" approved="yes">
<source>Open on GitHub</source>
<target xml:lang="zh-CN" state="needs-translation">Open on GitHub</target>
<target xml:lang="zh-CN" state="translated">在GitHub上打开</target>
<note/>
</trans-unit>
<trans-unit id="openLinkCommand|LocCanonicalName">
@ -152,7 +152,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.OpenLink</target>
<note/>
</trans-unit>
<trans-unit id="pullRequestCommand|ButtonText">
<trans-unit id="pullRequestCommand|ButtonText" approved="yes">
<source>Pull Requests</source>
<target xml:lang="zh-CN" state="translated">拉取请求</target>
<note/>
@ -162,7 +162,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.PullRequests</target>
<note/>
</trans-unit>
<trans-unit id="refreshCommand|ButtonText">
<trans-unit id="refreshCommand|ButtonText" approved="yes">
<source>Refresh</source>
<target xml:lang="zh-CN" state="translated">刷新</target>
<note/>
@ -172,7 +172,7 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.Refresh</target>
<note/>
</trans-unit>
<trans-unit id="showCurrentPullRequestCommand|ButtonText">
<trans-unit id="showCurrentPullRequestCommand|ButtonText" approved="yes">
<source>Show Current Pull Request</source>
<target xml:lang="zh-CN" state="translated">显示当前推送请求</target>
<note/>
@ -184,7 +184,7 @@
</trans-unit>
<trans-unit id="showGitHubPaneCommand|ButtonText">
<source>GitHub</source>
<target xml:lang="zh-CN" state="translated">GitHub</target>
<target xml:lang="zh-CN" state="needs-translation">GitHub</target>
<note/>
</trans-unit>
<trans-unit id="showGitHubPaneCommand|LocCanonicalName">
@ -192,9 +192,9 @@
<target xml:lang="zh-CN" state="needs-translation">.GitHub.ShowGitHubPane</target>
<note/>
</trans-unit>
<trans-unit id="syncSubmodulesCommand|ButtonText">
<trans-unit id="syncSubmodulesCommand|ButtonText" approved="yes">
<source>Sync Submodules</source>
<target xml:lang="zh-CN" state="needs-translation">Sync Submodules</target>
<target xml:lang="zh-CN" state="translated">同步子模块</target>
<note/>
</trans-unit>
<trans-unit id="syncSubmodulesCommand|LocCanonicalName">

Просмотреть файл

@ -27,8 +27,13 @@ public class RepositoryCloneServiceTests
await vsGitServices.Received().Clone("https://github.com/foo/bar", @"c:\dev\bar", true);
}
[Test]
public async Task UpdatesMetricsWhenRepositoryClonedAsync()
[TestCase("https://github.com/foo/bar", 1, nameof(UsageModel.MeasuresModel.NumberOfClones))]
[TestCase("https://github.com/foo/bar", 1, nameof(UsageModel.MeasuresModel.NumberOfGitHubClones))]
[TestCase("https://github.com/foo/bar", 0, nameof(UsageModel.MeasuresModel.NumberOfEnterpriseClones))]
[TestCase("https://enterprise.com/foo/bar", 1, nameof(UsageModel.MeasuresModel.NumberOfClones))]
[TestCase("https://enterprise.com/foo/bar", 1, nameof(UsageModel.MeasuresModel.NumberOfEnterpriseClones))]
[TestCase("https://enterprise.com/foo/bar", 0, nameof(UsageModel.MeasuresModel.NumberOfGitHubClones))]
public async Task UpdatesMetricsWhenRepositoryClonedAsync(string cloneUrl, int numberOfCalls, string counterName)
{
var serviceProvider = Substitutes.ServiceProvider;
var operatingSystem = serviceProvider.GetOperatingSystem();
@ -37,12 +42,12 @@ public class RepositoryCloneServiceTests
var usageTracker = Substitute.For<IUsageTracker>();
var cloneService = new RepositoryCloneService(operatingSystem, vsGitServices, graphqlFactory, usageTracker);
await cloneService.CloneRepository("https://github.com/foo/bar", @"c:\dev\bar");
await cloneService.CloneRepository(cloneUrl, @"c:\dev\bar");
var model = UsageModel.Create(Guid.NewGuid());
await usageTracker.Received().IncrementCounter(
await usageTracker.Received(numberOfCalls).IncrementCounter(
Arg.Is<Expression<Func<UsageModel.MeasuresModel, int>>>(x =>
((MemberExpression)x.Body).Member.Name == nameof(model.Measures.NumberOfClones)));
((MemberExpression)x.Body).Member.Name == counterName));
}
}
}

Просмотреть файл

@ -1,5 +1,8 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Threading.Tasks;
using GitHub.Extensions;
using GitHub.Models;
@ -26,6 +29,42 @@ namespace GitHub.App.UnitTests.ViewModels.Dialog.Clone
target.EnterpriseTab.DidNotReceiveWithAnyArgs().Initialize(null);
}
[TestCase("https://github.com", false, 0)]
[TestCase("https://enterprise.com", false, 1)]
[TestCase("https://github.com", true, 2, Description = "Show URL tab for GitHub connections")]
[TestCase("https://enterprise.com", true, 2, Description = "Show URL tab for Enterprise connections")]
public async Task Default_SelectedTabIndex_For_Group(string address, bool isGroupA, int expectTabIndex)
{
var cm = CreateConnectionManager(address);
var connection = cm.Connections[0];
var usageService = CreateUsageService(isGroupA);
var target = CreateTarget(connectionManager: cm, usageService: usageService);
await target.InitializeAsync(connection);
Assert.That(target.SelectedTabIndex, Is.EqualTo(expectTabIndex));
}
[TestCase("https://github.com", false, 1, nameof(UsageModel.MeasuresModel.NumberOfCloneViewGitHubTab))]
[TestCase("https://enterprise.com", false, 1, nameof(UsageModel.MeasuresModel.NumberOfCloneViewEnterpriseTab))]
[TestCase("https://github.com", true, 1, nameof(UsageModel.MeasuresModel.NumberOfCloneViewUrlTab))]
[TestCase("https://enterprise.com", true, 1, nameof(UsageModel.MeasuresModel.NumberOfCloneViewUrlTab))]
public async Task IncrementCounter_Showing_Default_Tab(string address, bool isGroupA, int numberOfCalls, string counterName)
{
var cm = CreateConnectionManager(address);
var connection = cm.Connections[0];
var usageService = CreateUsageService(isGroupA);
var usageTracker = Substitute.For<IUsageTracker>();
var target = CreateTarget(connectionManager: cm, usageService: usageService, usageTracker: usageTracker);
usageTracker.IncrementCounter(null).ReturnsForAnyArgs(Task.CompletedTask);
await target.InitializeAsync(connection).ConfigureAwait(false);
await usageTracker.Received(numberOfCalls).IncrementCounter(
Arg.Is<Expression<Func<UsageModel.MeasuresModel, int>>>(x =>
((MemberExpression)x.Body).Member.Name == counterName));
}
[Test]
public async Task EnterprisePage_Is_Initialized()
{
@ -274,6 +313,8 @@ namespace GitHub.App.UnitTests.ViewModels.Dialog.Clone
IOperatingSystem os = null,
IConnectionManager connectionManager = null,
IRepositoryCloneService service = null,
IUsageService usageService = null,
IUsageTracker usageTracker = null,
IRepositorySelectViewModel gitHubTab = null,
IRepositorySelectViewModel enterpriseTab = null,
IRepositoryUrlViewModel urlTab = null,
@ -282,6 +323,8 @@ namespace GitHub.App.UnitTests.ViewModels.Dialog.Clone
os = os ?? Substitute.For<IOperatingSystem>();
connectionManager = connectionManager ?? CreateConnectionManager("https://github.com");
service = service ?? CreateRepositoryCloneService(defaultClonePath);
usageService = usageService ?? CreateUsageService();
usageTracker = usageTracker ?? Substitute.For<IUsageTracker>();
gitHubTab = gitHubTab ?? CreateSelectViewModel();
enterpriseTab = enterpriseTab ?? CreateSelectViewModel();
urlTab = urlTab ?? Substitute.For<IRepositoryUrlViewModel>();
@ -290,11 +333,23 @@ namespace GitHub.App.UnitTests.ViewModels.Dialog.Clone
os,
connectionManager,
service,
usageService,
usageTracker,
gitHubTab,
enterpriseTab,
urlTab);
}
static IUsageService CreateUsageService(bool isGroupA = false)
{
var usageService = Substitute.For<IUsageService>();
var guidBytes = new byte[16];
guidBytes[guidBytes.Length - 1] = (byte)(isGroupA ? 0 : 1);
var userGuid = new Guid(guidBytes);
usageService.GetUserGuid().Returns(userGuid);
return usageService;
}
static IRepositoryModel CreateRepositoryModel(string repo = "owner/repo")
{
var split = repo.Split('/');