Skip to content

Commit

Permalink
Finish 9.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
rjmurillo committed Jan 19, 2018
2 parents 3efa72e + 32dd28d commit df2ad59
Show file tree
Hide file tree
Showing 165 changed files with 2,290 additions and 1,729 deletions.
45 changes: 31 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,67 @@ How often do you update a work item? How often do you create a new security grou
- v3 (VS 2015+ / NuGet 3.x): `https://www.myget.org/F/qwiq/api/v3/index.json`
- v2 (VS 2013 / NuGet 2.x): `https://www.myget.org/F/qwiq/api/v2`

Once the feed is configured, instald via the nuget UI (as [Microsoft.Qwiq.Core](https://www.myget.org/feed/qwiq/package/nuget/Microsoft.Qwiq.Core)), or via the nuget package manager console:
Once the feed is configured, install via the nuget UI or via the nuget package manager console

### Install Core
From the NuGet package manager console
```
PM> Install-Package Microsoft.Qwiq.Core
```
Or via the UI [Microsoft.Qwiq.Core](https://www.myget.org/feed/qwiq/package/nuget/Microsoft.Qwiq.Core),


### Install Client
We now have two clients: one for SOAP, and one for REST

From the NuGet package manager console
```
PM> Install-Package Microsoft.Qwiq.Client.Soap
```
Or via the UI [Microsoft.Qwiq.Client.Soap](https://www.myget.org/feed/qwiq/package/nuget/Microsoft.Qwiq.Client.Soap),

### Basic Usage
```csharp
using Microsoft.Qwiq;
using Microsoft.Qwiq.Credentials;

using Microsoft.VisualStudio.Services.Client;
...

// Create credentials objects based on the current process and OS identity
// We support
// - Username and password
// - PAT
// - Federated Windows credentials
var creds = CredentialsFactory.CreateCredentials();
var uri = new Uri("[Tfs Tenant Uri]");
// - OAuth2
// - Personal Access Token (PAT)
// - Username and password (BASIC)
// - Windows credentials (NTLM or Federated with Azure Active Directory)
// - Anonymous
// Use the full URI, including the collection. Example: https://QWIQ.VisualStudio.com/DefaultCollection
var uri = new Uri("[Tfs Tenant Uri]");
var options = new AuthenticationOptions(uri, AuthenticationType.Windows);
var store = WorkItemStoreFactory
.GetInstance()
.Create(uri, creds);
// ^^^ store and re-use this!
.Default
.Create(options);

// Execute WIQL
var items = store.Query(@"
SELECT [System.Id]
FROM WorkItems
WHERE WorkItemType = 'Bug' AND State = 'Active'");
WHERE [System.WorkItemType] = 'Bug' AND State = 'Active'");
```

```powershell
[Reflection.Assembly]::LoadFrom("E:\Path\To\Microsoft.Qwiq.Core.dll")
# Can use SOAP or REST clients here
[Reflection.Assembly]::LoadFrom("E:\Path\To\Microsoft.Qwiq.Client.Soap.dll")
$creds = [Microsoft.Qwiq.Credentials.CredentialsFactory]::CreateCredentials()
$uri = [Uri]"[Tfs Tenant Uri]"
$store = [Microsoft.Qwiq.WorkItemStoreFactory]::GetInstance().Create($uri, $creds)
$options = New-Object Microsoft.Qwiq.Credentials.AuthenticationOptions $uri,Windows
$store = [Microsoft.Qwiq.Client.Soap.WorkItemStoreFactory]::Default.Create($options)
$items = $store.Query(@"
SELECT [System.Id]
FROM WorkItems
WHERE WorkItemType = 'Bug' AND State = 'Active'")
WHERE [System.WorkItemType] = 'Bug' AND State = 'Active'", $false)
```

## Contributing
Expand Down
2 changes: 1 addition & 1 deletion src/Qwiq.Core.Rest/FieldDefinitionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal FieldDefinitionCollection(IEnumerable<WorkItemFieldReference> typeField
}

private FieldDefinitionCollection(List<IFieldDefinition> fieldDefinitions)
: base(fieldDefinitions)
: base(fieldDefinitions.Distinct().ToList())
{
}
}
Expand Down
85 changes: 85 additions & 0 deletions src/Qwiq.Core.Rest/LevelOrderEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;

namespace Microsoft.Qwiq.Client.Rest
{
internal class LevelOrderEnumerator : IEnumerator<WorkItemClassificationNode>
{
private readonly Queue<WorkItemClassificationNode> _queue;
private int _currentGenerationCount;
private int _nextGenerationCount;
private readonly WorkItemClassificationNode _root;
private readonly int? _maxDepth;
private int _currentDepth;

public LevelOrderEnumerator(WorkItemClassificationNode root, int? maxDepth = null)
{
_root = root;
_maxDepth = maxDepth;
_currentDepth = 0;
_queue = new Queue<WorkItemClassificationNode>();
_currentGenerationCount = 1;
_nextGenerationCount = 0;
Current = null;
}

public void Dispose()
{
}

public bool MoveNext()
{
if (Current == null)
{
Current = _root;
ProcessCurrent();

return true;
}

if (_queue.Count == 0)
{
return false;
}

if (_currentGenerationCount == 0)
{
_currentDepth++;
_currentGenerationCount = _nextGenerationCount;
_nextGenerationCount = 0;
}

Current = _queue.Dequeue();
ProcessCurrent();

return true;
}

private void ProcessCurrent()
{
_currentGenerationCount--;
if (_currentDepth >= _maxDepth) return;

Debug.Assert(Current != null, nameof(Current) + " != null");

if (Current.Children == null) return;

foreach (var child in Current.Children)
{
_nextGenerationCount++;
_queue.Enqueue(child);
}
}

public void Reset()
{
Current = null;
}

public WorkItemClassificationNode Current { get; private set; }

object IEnumerator.Current => Current;
}
}
33 changes: 0 additions & 33 deletions src/Qwiq.Core.Rest/Node.cs

This file was deleted.

36 changes: 3 additions & 33 deletions src/Qwiq.Core.Rest/Project.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;

using JetBrains.Annotations;

using Microsoft.TeamFoundation.Core.WebApi;
Expand Down Expand Up @@ -33,38 +32,9 @@ internal Project([NotNull] TeamProjectReference project, [NotNull] WorkItemStore
return new WorkItemTypeCollection(wits2);
}),
new Lazy<INodeCollection>(
() =>
{
var result = store.NativeWorkItemStore
.Value
.GetClassificationNodeAsync(
project.Id,
TreeStructureGroup.Areas,
null,
int.MaxValue)
.GetAwaiter()
.GetResult();
// SOAP Client does not return just the root, so return the root's children to match implementation
var n = new Node(result).ChildNodes;
return n;
}),
new Lazy<INodeCollection>(
() =>
{
var result = store.NativeWorkItemStore
.Value
.GetClassificationNodeAsync(
project.Name,
TreeStructureGroup.Iterations,
null,
int.MaxValue)
.GetAwaiter()
.GetResult();
return new Node(result).ChildNodes;
}))
new Lazy<IWorkItemClassificationNodeCollection<int>>(() => WorkItemClassificationNodeCollectionBuilder.BuildAsync(store.NativeWorkItemStore.Value.GetClassificationNodeAsync(project.Name, TreeStructureGroup.Areas, null, int.MaxValue)).GetAwaiter().GetResult()),
new Lazy<IWorkItemClassificationNodeCollection<int>>(() => WorkItemClassificationNodeCollectionBuilder.BuildAsync(store.NativeWorkItemStore.Value.GetClassificationNodeAsync(project.Name, TreeStructureGroup.Iterations, null, int.MaxValue)).GetAwaiter().GetResult())
)
{
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/Qwiq.Core.Rest/Qwiq.Client.Rest.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props')" />
<Import Project="..\..\packages\Microsoft.Net.Compilers.2.6.1\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\packages\Microsoft.Net.Compilers.2.6.1\build\Microsoft.Net.Compilers.props')" />
<Import Project="..\..\build\targets\common.props" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -84,8 +84,8 @@
<Compile Include="FieldDefinitionCollection.cs" />
<Compile Include="IdentityDescriptor.cs" />
<Compile Include="IInternalTeamProjectCollection.cs" />
<Compile Include="LevelOrderEnumerator.cs" />
<Compile Include="LinkCollection.cs" />
<Compile Include="Node.cs" />
<Compile Include="Project.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Query.cs" />
Expand All @@ -94,6 +94,7 @@
<Compile Include="TfsConnectionFactory.cs" />
<Compile Include="VssConnectionAdapter.cs" />
<Compile Include="WorkItem.cs" />
<Compile Include="WorkItemClassificationNodeCollectionBuilder.cs" />
<Compile Include="WorkItemLinkTypeEnd.cs" />
<Compile Include="WorkItemStore.cs" />
<Compile Include="WorkItemStoreConfiguration.cs" />
Expand All @@ -118,8 +119,8 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Net.Compilers.2.1.0\build\Microsoft.Net.Compilers.props'))" />
<Error Condition="!Exists('..\..\packages\GitVersionTask.4.0.0-beta0011\build\GitVersionTask.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\GitVersionTask.4.0.0-beta0011\build\GitVersionTask.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Net.Compilers.2.6.1\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Net.Compilers.2.6.1\build\Microsoft.Net.Compilers.props'))" />
</Target>
<Import Project="..\..\packages\GitVersionTask.4.0.0-beta0011\build\GitVersionTask.targets" Condition="Exists('..\..\packages\GitVersionTask.4.0.0-beta0011\build\GitVersionTask.targets')" />
</Project>
31 changes: 11 additions & 20 deletions src/Qwiq.Core.Rest/TeamFoundationIdentity.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System;
using JetBrains.Annotations;
using Microsoft.VisualStudio.Services.Identity;
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

using JetBrains.Annotations;

using Microsoft.VisualStudio.Services.Identity;

namespace Microsoft.Qwiq.Client.Rest
{
internal class TeamFoundationIdentity : Qwiq.TeamFoundationIdentity
Expand All @@ -15,35 +13,28 @@ internal class TeamFoundationIdentity : Qwiq.TeamFoundationIdentity

private readonly Identity _identity;

private readonly Lazy<IEnumerable<IIdentityDescriptor>> _memberOf;

private readonly Lazy<IEnumerable<IIdentityDescriptor>> _members;

internal TeamFoundationIdentity([NotNull] Identity identity)
: base(identity.IsActive, identity.Id, identity.UniqueUserId)
: base(
identity.IsActive,
identity.Id,
identity.UniqueUserId,
identity.MemberOf.Select(item => item.AsProxy()).ToArray(),
identity.Members.Select(item => item.AsProxy()).ToArray())
{
Contract.Requires(identity != null);

_identity = identity ?? throw new ArgumentNullException(nameof(identity));
DisplayName = identity.DisplayName;

IsContainer = identity.IsContainer;

_descriptor = new Lazy<IIdentityDescriptor>(() => identity.Descriptor.AsProxy());
_memberOf = new Lazy<IEnumerable<IIdentityDescriptor>>(() => identity.MemberOf.Select(item => item.AsProxy()));
_members = new Lazy<IEnumerable<IIdentityDescriptor>>(() => identity.Members.Select(item => item.AsProxy()));
}

public override IIdentityDescriptor Descriptor => _descriptor.Value;

public override string DisplayName { get; }

public override bool IsContainer { get; }

public override IEnumerable<IIdentityDescriptor> MemberOf => _memberOf.Value;

public override IEnumerable<IIdentityDescriptor> Members => _members.Value;

public override string GetAttribute(string name, string defaultValue)
{
if (_identity.Properties.TryGetValue(name, out object obj)) return obj?.ToString() ?? defaultValue;
Expand Down
7 changes: 2 additions & 5 deletions src/Qwiq.Core.Rest/TfsConnectionFactory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;

using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using System;

namespace Microsoft.Qwiq.Client.Rest
{
Expand All @@ -20,16 +19,14 @@ protected override ITeamProjectCollection ConnectToTfsCollection(Uri endpoint, V
tfsServer.Settings.BypassProxyOnLocal = true;
tfsServer.Settings.CompressionEnabled = true;



tfsServer.ConnectAsync(VssConnectMode.Automatic).GetAwaiter().GetResult();
if (!tfsServer.HasAuthenticated) throw new InvalidOperationException("Could not connect.");
return tfsServer.AsProxy();
}

// ReSharper disable ClassNeverInstantiated.Local
private class Nested
// ReSharper restore ClassNeverInstantiated.Local
// ReSharper restore ClassNeverInstantiated.Local
{
// ReSharper disable MemberHidesStaticFromOuterClass
internal static readonly TfsConnectionFactory Instance = new TfsConnectionFactory();
Expand Down
Loading

0 comments on commit df2ad59

Please sign in to comment.