Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
maartenba committed Oct 24, 2017
2 parents d1fb24e + a073486 commit 7c0c4f9
Show file tree
Hide file tree
Showing 29 changed files with 340 additions and 134 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,4 @@ fabric.properties
artifacts/
.vs/YouTrackSharp/v15/sqlite3/storage.ide
.idea/.idea.YouTrackSharp/.idea/inspectionProfiles/profiles_settings.xml
.idea/.idea.YouTrackSharp/.idea/contentModel.xml
6 changes: 0 additions & 6 deletions .idea/.idea.YouTrackSharp/.idea/contentModel.xml

This file was deleted.

7 changes: 7 additions & 0 deletions .idea/.idea.YouTrackSharp/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions YouTrackSharp.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=YouTrackSharp_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=YouTrackSharp/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="YouTrackSharp"&gt;&lt;AspOptimizeRegisterDirectives&gt;True&lt;/AspOptimizeRegisterDirectives&gt;&lt;HtmlReformatCode&gt;True&lt;/HtmlReformatCode&gt;&lt;JsInsertSemicolon&gt;True&lt;/JsInsertSemicolon&gt;&lt;FormatAttributeQuoteDescriptor&gt;True&lt;/FormatAttributeQuoteDescriptor&gt;&lt;CorrectVariableKindsDescriptor&gt;True&lt;/CorrectVariableKindsDescriptor&gt;&lt;VariablesToInnerScopesDescriptor&gt;True&lt;/VariablesToInnerScopesDescriptor&gt;&lt;StringToTemplatesDescriptor&gt;True&lt;/StringToTemplatesDescriptor&gt;&lt;JsReformatCode&gt;True&lt;/JsReformatCode&gt;&lt;RemoveRedundantQualifiersTs&gt;True&lt;/RemoveRedundantQualifiersTs&gt;&lt;OptimizeImportsTs&gt;True&lt;/OptimizeImportsTs&gt;&lt;OptimizeReferenceCommentsTs&gt;True&lt;/OptimizeReferenceCommentsTs&gt;&lt;PublicModifierStyleTs&gt;True&lt;/PublicModifierStyleTs&gt;&lt;ExplicitAnyTs&gt;True&lt;/ExplicitAnyTs&gt;&lt;TypeAnnotationStyleTs&gt;True&lt;/TypeAnnotationStyleTs&gt;&lt;RelativePathStyleTs&gt;True&lt;/RelativePathStyleTs&gt;&lt;AsInsteadOfCastTs&gt;True&lt;/AsInsteadOfCastTs&gt;&lt;CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="False" /&gt;&lt;CSEnforceVarKeywordUsageSettings&gt;True&lt;/CSEnforceVarKeywordUsageSettings&gt;&lt;RemoveCodeRedundanciesVB&gt;True&lt;/RemoveCodeRedundanciesVB&gt;&lt;CssAlphabetizeProperties&gt;True&lt;/CssAlphabetizeProperties&gt;&lt;VBOptimizeImports&gt;True&lt;/VBOptimizeImports&gt;&lt;VBShortenReferences&gt;True&lt;/VBShortenReferences&gt;&lt;CSUseAutoProperty&gt;True&lt;/CSUseAutoProperty&gt;&lt;CSMakeAutoPropertyGetOnly&gt;True&lt;/CSMakeAutoPropertyGetOnly&gt;&lt;CSArrangeQualifiers&gt;True&lt;/CSArrangeQualifiers&gt;&lt;CSFixBuiltinTypeReferences&gt;True&lt;/CSFixBuiltinTypeReferences&gt;&lt;CssReformatCode&gt;True&lt;/CssReformatCode&gt;&lt;VBReformatCode&gt;True&lt;/VBReformatCode&gt;&lt;VBFormatDocComments&gt;True&lt;/VBFormatDocComments&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">YouTrackSharp</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/USE_INDENT_FROM_VS/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
4 changes: 1 addition & 3 deletions src/YouTrackSharp/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ public abstract class Connection
/// </exception>
protected Connection(string serverUrl)
{
Uri serverUri;

if (string.IsNullOrEmpty(serverUrl)
|| !Uri.TryCreate(EnsureTrailingSlash(serverUrl), UriKind.Absolute, out serverUri))
|| !Uri.TryCreate(EnsureTrailingSlash(serverUrl), UriKind.Absolute, out var serverUri))
{
throw new ArgumentException("The server URL is invalid. Please provide a valid URL to a self-hosted YouTrack instance or YouTrack InCloud.", nameof(serverUrl));
}
Expand Down
37 changes: 37 additions & 0 deletions src/YouTrackSharp/Issues/Change.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

namespace YouTrackSharp.Issues
{
/// <summary>
/// A class that represents a YouTrack issue change.
/// </summary>
public class Change
{
/// <summary>
/// Creates an instance of the <see cref="Change" /> class.
/// </summary>
public Change()
{
Fields = new List<FieldChange>();
}

/// <summary>
/// Fields that have been changed.
/// </summary>
[JsonProperty("field")]
public ICollection<FieldChange> Fields { get; set; }

/// <summary>
/// Get <see cref="FieldChange"/> for a field identified by <paramref name="fieldName"/>.
/// </summary>
/// <param name="fieldName">Name of the field to retrieve <see cref="FieldChange"/> for.</param>
/// <returns><see cref="FieldChange"/> for a field identified by <paramref name="fieldName"/>. Can be <value>null</value>.</returns>
public FieldChange ForField(string fieldName)
{
return Fields.FirstOrDefault(field => string.Equals(field.Name, fieldName, StringComparison.OrdinalIgnoreCase));
}
}
}
17 changes: 17 additions & 0 deletions src/YouTrackSharp/Issues/ChangeCollectionWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace YouTrackSharp.Issues
{
/// <summary>
/// Wrapper for <see cref="T:System.Collections.Generic.ICollection`1" /> of <see cref="Change" />.
/// </summary>
internal class ChangeCollectionWrapper
{
/// <summary>
/// Wrapped <see cref="T:System.Collections.Generic.ICollection`1" /> of <see cref="Change" />.
/// </summary>
[JsonProperty("change")]
public ICollection<Change> Changes { get; set; }
}
}
56 changes: 24 additions & 32 deletions src/YouTrackSharp/Issues/Field.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,14 @@ public class Field
/// <returns><see cref="Value" /> as <see cref="T:System.String"/>.</returns>
public string AsString()
{
if (Value == null)
switch (Value)
{
return null;
case null:
return null;
case ICollection<string> collection:
return collection.SingleOrDefault();
}

if (Value is ICollection<string> collection)
{
return collection.SingleOrDefault();
}


return Value.ToString();
}

Expand All @@ -61,20 +59,17 @@ public string AsString()
/// <returns><see cref="Value" /> as <see cref="T:System.Collections.Generic.ICollection{System.String}"/>.</returns>
public ICollection<string> AsCollection()
{
if (Value == null)
{
return new List<string>();
}
else if (Value is ICollection<string> collection)
switch (Value)
{
return collection;
}
else
{
return new List<string>()
{
Value.ToString()
};
case null:
return new List<string>();
case ICollection<string> collection:
return collection;
default:
return new List<string>
{
Value.ToString()
};
}
}

Expand All @@ -84,19 +79,16 @@ public ICollection<string> AsCollection()
/// <returns><see cref="Value" /> as <see cref="T:System.DateTime"/>.</returns>
public DateTime AsDateTime()
{
if (Value is DateTime dateTime)
{
return dateTime;
}
else if (Value is DateTimeOffset dateTimeOffset)
{
return dateTimeOffset.DateTime;
}
else
switch (Value)
{
var milliseconds = Convert.ToInt64(AsString());
case DateTime dateTime:
return dateTime;
case DateTimeOffset dateTimeOffset:
return dateTimeOffset.DateTime;
default:
var milliseconds = Convert.ToInt64(AsString());

return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds).DateTime;
return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds).DateTime;
}
}

Expand Down
88 changes: 88 additions & 0 deletions src/YouTrackSharp/Issues/FieldChange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Diagnostics;
using Newtonsoft.Json;

namespace YouTrackSharp.Issues
{
/// <summary>
/// Represents a YouTrack issue field change.
/// </summary>
[DebuggerDisplay("{Name}: {GetDebuggerTransition()}")]
public class FieldChange
{
#region JsonProperties

[JsonProperty("oldValue")]
// ReSharper disable once InconsistentNaming
private object _oldValue
{
get => From.Value;
set => From.Value = value;
}

[JsonProperty("value")]
// ReSharper disable once InconsistentNaming
private object _value
{
get => To.Value;
set => To.Value = value;
}

[JsonProperty("newValue")]
// ReSharper disable once InconsistentNaming
private object _newValue
{
get => To.Value;
set => To.Value = value;
}

#endregion

/// <summary>
/// Creates an instance of the <see cref="FieldChange" /> class.
/// </summary>
public FieldChange()
{
From = new Field();
To = new Field();
}

/// <summary>
/// Name of the field.
/// </summary>
[JsonProperty("name")]
public string Name
{
get => To.Name;
private set
{
From.Name = value;
To.Name = value;
}
}

/// <summary>
/// <see cref="Field" /> representing the original value. Can be <value>null</value>.
/// </summary>
[JsonIgnore]
public Field From { get; }

/// <summary>
/// <see cref="Field" /> representing the new value. Can be <value>null</value>.
/// </summary>
[JsonIgnore]
public Field To { get; }

/// <summary>
/// Is this a transition from an older value to a newer one?
/// </summary>
[JsonIgnore]
public bool IsTransition => From.Value != null;

private string GetDebuggerTransition()
{
return IsTransition
? $"{From.Value} -> {To.Value}"
: To.Value.ToString();
}
}
}
14 changes: 4 additions & 10 deletions src/YouTrackSharp/Issues/Issue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ public string Description {
/// <summary>
/// Issue fields.
/// </summary>
public ICollection<Field> Fields
{
get { return _fields.Values; }
}
public ICollection<Field> Fields => _fields.Values;

/// <summary>
/// Issue comments.
Expand All @@ -97,8 +94,7 @@ public ICollection<Field> Fields
/// <returns><see cref="Field"/> matching the <paramref name="fieldName"/>; null when not found.</returns>
public Field GetField(string fieldName)
{
Field field;
_fields.TryGetValue(fieldName, out field);
_fields.TryGetValue(fieldName, out var field);
return field;
}

Expand All @@ -109,8 +105,7 @@ public Field GetField(string fieldName)
/// <param name="value">The value to set for the <see cref="Field"/>.</param>
public void SetField(string fieldName, object value)
{
Field field;
if (_fields.TryGetValue(fieldName, out field))
if (_fields.TryGetValue(fieldName, out var field))
{
field.Value = value;
}
Expand Down Expand Up @@ -177,8 +172,7 @@ public override bool TrySetMember(SetMemberBinder binder, object value)
}

// Regular setter
Field field;
if (_fields.TryGetValue(binder.Name, out field) || _fields.TryGetValue(binder.Name.Replace("_", " "), out field))
if (_fields.TryGetValue(binder.Name, out var field) || _fields.TryGetValue(binder.Name.Replace("_", " "), out field))
{
field.Value = value;
}
Expand Down
12 changes: 7 additions & 5 deletions src/YouTrackSharp/Issues/IssuesService.Attachments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public async Task AttachFileToIssue(string issueId, string attachmentName, Strea
{
queryString.Add($"attachmentName={attachmentName}");
}
if (!string.IsNullOrEmpty(@group))
if (!string.IsNullOrEmpty(group))
{
queryString.Add($"group={@group}");
queryString.Add($"group={group}");
}
if (!string.IsNullOrEmpty(@group))
if (!string.IsNullOrEmpty(group))
{
queryString.Add($"author={author}");
}
Expand All @@ -61,8 +61,10 @@ public async Task AttachFileToIssue(string issueId, string attachmentName, Strea
Name = attachmentName
};

var content = new MultipartFormDataContent();
content.Add(streamContent);
var content = new MultipartFormDataContent
{
streamContent
};

var client = await _connection.GetAuthenticatedHttpClient();
var response = await client.PostAsync($"rest/issue/{issueId}/attachment?{query}", content);
Expand Down
34 changes: 34 additions & 0 deletions src/YouTrackSharp/Issues/IssuesService.History.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace YouTrackSharp.Issues
{
public partial class IssuesService
{
/// <summary>
/// Get change history for a specific issue from the server.
/// </summary>
/// <remarks>Uses the REST API <a href="https://www.jetbrains.com/help/youtrack/standalone/Get-Historical-Changes-of-an-Issue.html">Get Changes of an Issue</a>.</remarks>
/// <param name="issueId">Id of the issue to get change history for.</param>
/// <returns>An <see cref="T:System.Collections.Generic.IEnumerable`1" /> of <see cref="Change" /> for the requested issue <paramref name="issueId"/>.</returns>
/// <exception cref="T:System.ArgumentNullException">When the <paramref name="issueId"/> is null or empty.</exception>
/// <exception cref="T:System.Net.HttpRequestException">When the call to the remote YouTrack server instance failed.</exception>
public async Task<IEnumerable<Change>> GetChangeHistoryForIssue(string issueId)
{
if (string.IsNullOrEmpty(issueId))
{
throw new ArgumentNullException(nameof(issueId));
}

var client = await _connection.GetAuthenticatedHttpClient();
var response = await client.GetAsync($"rest/issue/{issueId}/changes");

response.EnsureSuccessStatusCode();

var wrapper = JsonConvert.DeserializeObject<ChangeCollectionWrapper>(await response.Content.ReadAsStringAsync());
return wrapper.Changes;
}
}
}
Loading

0 comments on commit 7c0c4f9

Please sign in to comment.