Front end for uploading a release asset.

This commit is contained in:
Matt Burke
2013-10-02 14:55:05 -04:00
committed by Haacked
parent 9a6e46d608
commit 15a5cc9591
8 changed files with 124 additions and 0 deletions
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using NSubstitute;
@@ -189,5 +191,35 @@ namespace Octokit.Tests.Clients
await AssertEx.Throws<ArgumentNullException>(async () => await repositoriesClient.CreateRelease("owner", "name", null));
}
}
public class TheUploadReleaseAssetMethod
{
[Fact]
public void UploadsToCorrectUrl()
{
var client = Substitute.For<IApiConnection<Repository>>();
var repositoriesClient = new RepositoriesClient(client);
var release = new Release { UploadUrl = "https://uploads.test.dev/does/not/matter/releases/1/assets{?name}" };
var rawData = Substitute.For<Stream>();
var upload = new ReleaseAssetUpload { FileName = "example.zip", ContentType = "application/zip", RawData = rawData };
repositoriesClient.UploadAsset(release, upload);
client.Received().Upload<ReleaseAsset>(Arg.Is<Uri>(u => u.ToString() == "https://uploads.test.dev/does/not/matter/releases/1/assets?name=example.zip"),
rawData,
Arg.Is<Dictionary<string, string>>(headers => headers["Content-Type"] == "application/zip"));
}
[Fact]
public async Task EnsuresArgumentsNotNull()
{
var repositoriesClient = new RepositoriesClient(Substitute.For<IApiConnection<Repository>>());
var release = new Release { UploadUrl = "https://uploads.github.com/anything" };
var uploadData = new ReleaseAssetUpload { FileName = "good", ContentType = "good/good", RawData = Stream.Null };
await AssertEx.Throws<ArgumentNullException>(async () => await repositoriesClient.UploadAsset(null, uploadData));
await AssertEx.Throws<ArgumentNullException>(async () => await repositoriesClient.UploadAsset(release, null));
}
}
}
}
@@ -50,5 +50,17 @@ namespace Octokit.Tests.Helpers
Assert.Throws<ArgumentException>(() => "".ToRubyCase());
}
}
public class TheExpandUriTemplateMethod
{
[Theory]
[InlineData("https://host.com/path?name=other", "https://host.com/path?name=other")]
[InlineData("https://host.com/path?name=example name.txt", "https://host.com/path{?name}")]
[InlineData("https://host.com/path", "https://host.com/path{?other}")]
public void ExpandsUriTemplates(string expected, string template)
{
Assert.Equal(expected, template.ExpandUriTemplate(new { name = "example name.txt" }).ToString());
}
}
}
}
+10
View File
@@ -73,5 +73,15 @@ namespace Octokit.Clients
var endpoint = "/repos/{0}/{1}/releases".FormatUri(owner, name);
return await Client.Create<Release>(endpoint, data);
}
public async Task<ReleaseAsset> UploadAsset(Release release, ReleaseAssetUpload data)
{
Ensure.ArgumentNotNull(release, "release");
Ensure.ArgumentNotNull(data, "data");
var endpoint = release.UploadUrl.ExpandUriTemplate(new { name = data.FileName });
return await Client.Upload<ReleaseAsset>(endpoint, data.RawData, new Dictionary<string, string> { { "Content-Type", data.ContentType } });
}
}
}
+22
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Octokit.Http;
@@ -489,6 +490,27 @@ namespace Octokit
public bool Prerelease { get; set; }
}
public class ReleaseAsset
{
public string Url { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public string Label { get; set; }
public string State { get; set; }
public string ContentType { get; set; }
public int Size { get; set; }
public int DownloadCount { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
}
public class ReleaseAssetUpload
{
public string FileName { get; set; }
public string ContentType { get; set; }
public Stream RawData { get; set; }
}
public class ApiError
{
public string Message { get; set; }
+32
View File
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Octokit
{
@@ -24,6 +26,36 @@ namespace Octokit
return new Uri(string.Format(CultureInfo.InvariantCulture, pattern, args), UriKind.Relative);
}
static Regex OptionalQueryStringRegex = new Regex("\\{\\?([^}]+)\\}");
public static Uri ExpandUriTemplate(this string template, object values)
{
var optionalQueryStringMatch = OptionalQueryStringRegex.Match(template);
if(optionalQueryStringMatch.Success)
{
var expansion = "";
var parameterName = optionalQueryStringMatch.Groups[1].Value;
var parameterProperty = values.GetType().GetProperty(parameterName);
if(parameterProperty != null)
{
expansion = "?" + parameterName + "=" + Uri.EscapeDataString("" + parameterProperty.GetValue(values, new object[0]));
}
template = OptionalQueryStringRegex.Replace(template, expansion);
}
return new Uri(template);
}
#if NETFX_CORE
public static PropertyInfo GetProperty(this Type t, string propertyName)
{
return t.GetTypeInfo().GetDeclaredProperty(propertyName);
}
#endif
public static string EscapeUri(this string s)
{
return Uri.EscapeUriString(s);
}
// :trollface:
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase",
Justification = "Ruby don't care. Ruby don't play that.")]
+5
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Octokit.Clients;
@@ -124,5 +125,9 @@ namespace Octokit.Http
return new ReadOnlyPagedCollection<TOther>(response, Connection);
}
public Task<TOther> Upload<TOther>(Uri uri, Stream rawData, Dictionary<string, string> headers)
{
throw new NotImplementedException();
}
}
}
+2
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
namespace Octokit.Http
@@ -22,5 +23,6 @@ namespace Octokit.Http
Task<TOther> Create<TOther>(Uri endpoint, object data);
Task<T> Update(Uri endpoint, object data);
Task Delete(Uri endpoint);
Task<TOther> Upload<TOther>(Uri uri, Stream rawData, Dictionary<string, string> headers);
}
}
+9
View File
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
namespace Octokit
@@ -73,5 +74,13 @@ namespace Octokit
/// <param name="data">The data for the release.</param>
/// <returns>A new <see cref="Release"/>.</returns>
Task<Release> CreateRelease(string owner, string name, ReleaseUpdate data);
/// <summary>
/// Upload a <see cref="ReleaseAsset"/> for the specified release.
/// </summary>
/// <param name="release">The <see cref="Release"/> to attach the asset to.</param>
/// <param name="data">The asset information.</param>
/// <returns>A new <see cref="ReleaseAsset"/>.</returns>
Task<ReleaseAsset> UploadAsset(Release release, ReleaseAssetUpload data);
}
}