From b95a6ff54c3fed4943884d14bdb878a89521f463 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:07:57 +0100 Subject: [PATCH 01/16] Methods for interacting with artifacts for ActionsArtifactsClient.cs --- Octokit.Tests/Models/ArtifactsTests.cs | 98 +++++++++++++++++++ Octokit/Clients/ActionsArtifactsClient.cs | 50 +++++++++- Octokit/Clients/IActionsArtifactsClient.cs | 6 ++ Octokit/Helpers/ApiUrls.cs | 47 +++++++++ Octokit/Helpers/Ensure.cs | 12 +++ Octokit/Models/Response/Artifact.cs | 18 ++++ .../Models/Response/ArtifactWorkflowRun.cs | 8 ++ .../Models/Response/ListArtifactsResponse.cs | 7 ++ 8 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 Octokit.Tests/Models/ArtifactsTests.cs create mode 100644 Octokit/Models/Response/Artifact.cs create mode 100644 Octokit/Models/Response/ArtifactWorkflowRun.cs create mode 100644 Octokit/Models/Response/ListArtifactsResponse.cs diff --git a/Octokit.Tests/Models/ArtifactsTests.cs b/Octokit.Tests/Models/ArtifactsTests.cs new file mode 100644 index 0000000000..3cb1cff7a1 --- /dev/null +++ b/Octokit.Tests/Models/ArtifactsTests.cs @@ -0,0 +1,98 @@ +using System; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class ArtifactsTests + { + [Fact] + public void CanBeDeserialized() + { + var json = @"{ + ""total_count"": 2, + ""artifacts"": [ + { + ""id"": 11, + ""node_id"": ""MDg6QXJ0aWZhY3QxMQ=="", + ""name"": ""Rails"", + ""size_in_bytes"": 556, + ""url"": ""https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/11"", + ""archive_download_url"": ""https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/11/zip"", + ""expired"": false, + ""created_at"": ""2020-01-10T14:59:22Z"", + ""expires_at"": ""2020-03-21T14:59:22Z"", + ""updated_at"": ""2020-02-21T14:59:22Z"", + ""workflow_run"": { + ""id"": 2332938, + ""repository_id"": 1296269, + ""head_repository_id"": 1296269, + ""head_branch"": ""main"", + ""head_sha"": ""328faa0536e6fef19753d9d91dc96a9931694ce3"" + } + }, + { + ""id"": 13, + ""node_id"": ""MDg6QXJ0aWZhY3QxMw=="", + ""name"": ""Test output"", + ""size_in_bytes"": 453, + ""url"": ""https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/13"", + ""archive_download_url"": ""https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/13/zip"", + ""expired"": false, + ""created_at"": ""2020-01-10T14:59:22Z"", + ""expires_at"": ""2020-03-21T14:59:22Z"", + ""updated_at"": ""2020-02-21T14:59:22Z"", + ""workflow_run"": { + ""id"": 2332942, + ""repository_id"": 1296269, + ""head_repository_id"": 1296269, + ""head_branch"": ""main"", + ""head_sha"": ""178f4f6090b3fccad4a65b3e83d076a622d59652"" + } + } + ] +}"; + + var serializer = new SimpleJsonSerializer(); + + var payload = serializer.Deserialize(json); + + Assert.NotNull(payload); + + Assert.Equal(2, payload.TotalCount); + Assert.Equal(2, payload.Artifacts.Count); + + Assert.Equal(11, payload.Artifacts[0].Id); + Assert.Equal("MDg6QXJ0aWZhY3QxMQ==", payload.Artifacts[0].NodeId); + Assert.Equal("Rails", payload.Artifacts[0].Name); + Assert.Equal(556, payload.Artifacts[0].SizeInBytes); + Assert.Equal("https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/11", payload.Artifacts[0].Url); + Assert.Equal("https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/11/zip", payload.Artifacts[0].ArchiveDownloadUrl); + Assert.False(payload.Artifacts[0].Expired); + Assert.Equal(new DateTime(2020, 1, 10, 14, 59, 22, DateTimeKind.Utc), payload.Artifacts[0].CreatedAt); + Assert.Equal(new DateTime(2020, 3, 21, 14, 59, 22, DateTimeKind.Utc), payload.Artifacts[0].ExpiresAt); + Assert.Equal(new DateTime(2020, 2, 21, 14, 59, 22, DateTimeKind.Utc), payload.Artifacts[0].UpdatedAt); + Assert.Equal(2332938, payload.Artifacts[0].WorkflowRun.Id); + Assert.Equal(1296269, payload.Artifacts[0].WorkflowRun.RepositoryId); + Assert.Equal(1296269, payload.Artifacts[0].WorkflowRun.HeadRepositoryId); + Assert.Equal("main", payload.Artifacts[0].WorkflowRun.HeadBranch); + Assert.Equal("328faa0536e6fef19753d9d91dc96a9931694ce3", payload.Artifacts[0].WorkflowRun.HeadSha); + + Assert.Equal(13, payload.Artifacts[1].Id); + Assert.Equal("MDg6QXJ0aWZhY3QxMw==", payload.Artifacts[1].NodeId); + Assert.Equal("Test output", payload.Artifacts[1].Name); + Assert.Equal(453, payload.Artifacts[1].SizeInBytes); + Assert.Equal("https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/13", payload.Artifacts[1].Url); + Assert.Equal("https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/13/zip", payload.Artifacts[1].ArchiveDownloadUrl); + Assert.False(payload.Artifacts[1].Expired); + Assert.Equal(new DateTime(2020, 1, 10, 14, 59, 22, DateTimeKind.Utc), payload.Artifacts[1].CreatedAt); + Assert.Equal(new DateTime(2020, 3, 21, 14, 59, 22, DateTimeKind.Utc), payload.Artifacts[1].ExpiresAt); + Assert.Equal(new DateTime(2020, 2, 21, 14, 59, 22, DateTimeKind.Utc), payload.Artifacts[1].UpdatedAt); + Assert.Equal(2332942, payload.Artifacts[1].WorkflowRun.Id); + Assert.Equal(1296269, payload.Artifacts[1].WorkflowRun.RepositoryId); + Assert.Equal(1296269, payload.Artifacts[1].WorkflowRun.HeadRepositoryId); + Assert.Equal("main", payload.Artifacts[1].WorkflowRun.HeadBranch); + Assert.Equal("178f4f6090b3fccad4a65b3e83d076a622d59652", payload.Artifacts[1].WorkflowRun.HeadSha); + } + } +} diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index cc57d0c433..ab0df58dd5 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -1,4 +1,7 @@ -namespace Octokit +using System.IO; +using System.Threading.Tasks; + +namespace Octokit { /// /// A client for GitHub's Actions Artifacts API. @@ -15,5 +18,50 @@ public class ActionsArtifactsClient : ApiClient, IActionsArtifactsClient public ActionsArtifactsClient(IApiConnection apiConnection) : base(apiConnection) { } + + public Task ListArtifacts(string owner, string repository) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); + + return ApiConnection.Get(ApiUrls.ListArtifacts(owner, repository), null); + } + + public Task GetArtifact(string owner, string repository, int artifactId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); + Ensure.ArgumentNotNullOrDefault(artifactId, nameof(artifactId)); + + return ApiConnection.Get(ApiUrls.Artifact(owner, repository, artifactId), null); + } + + public Task DeleteArtifact(string owner, string repository, int artifactId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); + Ensure.ArgumentNotNullOrDefault(artifactId, nameof(artifactId)); + + return ApiConnection.Delete(ApiUrls.Artifact(owner, repository, artifactId), null); + } + + public Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); + Ensure.ArgumentNotNullOrDefault(artifactId, nameof(artifactId)); + Ensure.ArgumentNotNullOrEmptyString(repository, nameof(archiveFormat)); + + return ApiConnection.GetRaw(ApiUrls.DownloadArtifact(owner, repository, artifactId, archiveFormat), null); + } + + public Task ListWorkflowArtifacts(string owner, string repository, int runId) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); + Ensure.ArgumentNotNullOrDefault(runId, nameof(runId)); + + return ApiConnection.Get(ApiUrls.ListWorkflowArtifacts(owner, repository, runId), null); + } } } diff --git a/Octokit/Clients/IActionsArtifactsClient.cs b/Octokit/Clients/IActionsArtifactsClient.cs index 9905bad9cb..f464838961 100644 --- a/Octokit/Clients/IActionsArtifactsClient.cs +++ b/Octokit/Clients/IActionsArtifactsClient.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; namespace Octokit @@ -11,5 +12,10 @@ namespace Octokit /// public interface IActionsArtifactsClient { + Task ListArtifacts(string owner, string repository); + Task GetArtifact(string owner, string repository, int artifactId); + Task DeleteArtifact(string owner, string repository, int artifactId); + Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); + Task ListWorkflowArtifacts(string owner, string repository, int runId); } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 20765f96cc..bf467fbf65 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -5472,5 +5472,52 @@ public static Uri CodespaceStop(string codespaceName) { return "user/codespaces/{0}/stop".FormatUri(codespaceName); } + + /// + /// Returns the that lists the artifacts for a repository. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri ListArtifacts(string owner, string repository) + { + return "repos/{0}/{1}/actions/artifacts".FormatUri(owner, repository); + } + + /// + /// Returns the for the specified artifact. + /// + /// The owner of the repository + /// The name of the repository + /// The id of the artifact + /// + public static Uri Artifact(string owner, string repository, int artifactId) + { + return "repos/{0}/{1}/actions/artifacts/{2}".FormatUri(owner, repository, artifactId); + } + + /// + /// Returns the to download the specified artifact. + /// + /// The owner of the repository + /// The name of the repository + /// The id of the artifact + /// + public static Uri DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + { + return "repos/{0}/{1}/actions/artifacts/{2}/{3}".FormatUri(owner, repository, artifactId); + } + + /// + /// Returns the to list the artifacts for a workflow. + /// + /// The owner of the repository + /// The name of the repository + /// The id of the workflow run + /// + public static Uri ListWorkflowArtifacts(string owner, string repository, int runId) + { + return "repos/{0}/{1}/actions/runs/{2}/artifacts".FormatUri(owner, repository, runId); + } } } diff --git a/Octokit/Helpers/Ensure.cs b/Octokit/Helpers/Ensure.cs index 77204d9531..b028156ceb 100644 --- a/Octokit/Helpers/Ensure.cs +++ b/Octokit/Helpers/Ensure.cs @@ -21,6 +21,18 @@ public static void ArgumentNotNull([ValidatedNotNull]object value, string name) throw new ArgumentNullException(name); } + + /// + /// Checks an argument to ensure it isn't null or the default value. + /// + /// The argument value to check + /// The name of the argument + public static void ArgumentNotNullOrDefault([ValidatedNotNull]T value, string name) + { + if (value != null && !EqualityComparer.Default.Equals(value, default)) return; + + throw new ArgumentNullException(name); + } /// /// Checks a string argument to ensure it isn't null or empty. diff --git a/Octokit/Models/Response/Artifact.cs b/Octokit/Models/Response/Artifact.cs new file mode 100644 index 0000000000..35d71efc47 --- /dev/null +++ b/Octokit/Models/Response/Artifact.cs @@ -0,0 +1,18 @@ +// Root myDeserializedClass = JsonConvert.DeserializeObject(myJsonResponse); + +using System; + +public class Artifact +{ + public int Id { get; private set; } + public string NodeId { get; private set; } + public string Name { get; private set; } + public int SizeInBytes { get; private set; } + public string Url { get; private set; } + public string ArchiveDownloadUrl { get; private set; } + public bool Expired { get; private set; } + public DateTime CreatedAt { get; private set; } + public DateTime ExpiresAt { get; private set; } + public DateTime UpdatedAt { get; private set; } + public ArtifactWorkflowRun WorkflowRun { get; private set; } +} \ No newline at end of file diff --git a/Octokit/Models/Response/ArtifactWorkflowRun.cs b/Octokit/Models/Response/ArtifactWorkflowRun.cs new file mode 100644 index 0000000000..3b34e7cb45 --- /dev/null +++ b/Octokit/Models/Response/ArtifactWorkflowRun.cs @@ -0,0 +1,8 @@ +public class ArtifactWorkflowRun +{ + public int Id { get; private set; } + public int RepositoryId { get; private set; } + public int HeadRepositoryId { get; private set; } + public string HeadBranch { get; private set; } + public string HeadSha { get; private set; } +} diff --git a/Octokit/Models/Response/ListArtifactsResponse.cs b/Octokit/Models/Response/ListArtifactsResponse.cs new file mode 100644 index 0000000000..eac94df351 --- /dev/null +++ b/Octokit/Models/Response/ListArtifactsResponse.cs @@ -0,0 +1,7 @@ +using System.Collections.Generic; + +public class ListArtifactsResponse +{ + public int TotalCount { get; private set; } + public IReadOnlyList Artifacts { get; private set; } = new List(); +} \ No newline at end of file From 28e931cb3ed3fb821c6ddd7d0002cac6d9163310 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:14:03 +0100 Subject: [PATCH 02/16] Tidy usings --- Octokit/Clients/ActionsArtifactsClient.cs | 3 +-- Octokit/Clients/IActionsArtifactsClient.cs | 4 +--- Octokit/Models/Response/Artifact.cs | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index ab0df58dd5..6c22e22da5 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -1,5 +1,4 @@ -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Octokit { diff --git a/Octokit/Clients/IActionsArtifactsClient.cs b/Octokit/Clients/IActionsArtifactsClient.cs index f464838961..0300f8bd8e 100644 --- a/Octokit/Clients/IActionsArtifactsClient.cs +++ b/Octokit/Clients/IActionsArtifactsClient.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Octokit { diff --git a/Octokit/Models/Response/Artifact.cs b/Octokit/Models/Response/Artifact.cs index 35d71efc47..1c2b948ed5 100644 --- a/Octokit/Models/Response/Artifact.cs +++ b/Octokit/Models/Response/Artifact.cs @@ -1,6 +1,4 @@ -// Root myDeserializedClass = JsonConvert.DeserializeObject(myJsonResponse); - -using System; +using System; public class Artifact { From 1d5f35c8900fd91bfdaad07d851d31d1b904d987 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:20:54 +0100 Subject: [PATCH 03/16] Xml comments --- Octokit/Models/Response/Artifact.cs | 43 +++++++++++++++++++ .../Models/Response/ArtifactWorkflowRun.cs | 19 ++++++++ .../Models/Response/ListArtifactsResponse.cs | 7 +++ 3 files changed, 69 insertions(+) diff --git a/Octokit/Models/Response/Artifact.cs b/Octokit/Models/Response/Artifact.cs index 1c2b948ed5..a97182be09 100644 --- a/Octokit/Models/Response/Artifact.cs +++ b/Octokit/Models/Response/Artifact.cs @@ -2,15 +2,58 @@ public class Artifact { + /// + /// The artifact Id + /// public int Id { get; private set; } + + /// + /// The artifact node Id + /// public string NodeId { get; private set; } + + /// + /// The name of the artifact + /// public string Name { get; private set; } + + /// + /// The size of the artifact in bytes + /// public int SizeInBytes { get; private set; } + + /// + /// The url for retrieving the artifact information + /// public string Url { get; private set; } + + /// + /// The url for downloading the artifact contents + /// public string ArchiveDownloadUrl { get; private set; } + + /// + /// True if the artifact has expired + /// public bool Expired { get; private set; } + + /// + /// The date and time when the artifact was created + /// public DateTime CreatedAt { get; private set; } + + /// + /// The date and time when the artifact expires + /// public DateTime ExpiresAt { get; private set; } + + /// + /// The date and time when the artifact was last updated + /// public DateTime UpdatedAt { get; private set; } + + /// + /// The workflow from where the artifact was created + /// public ArtifactWorkflowRun WorkflowRun { get; private set; } } \ No newline at end of file diff --git a/Octokit/Models/Response/ArtifactWorkflowRun.cs b/Octokit/Models/Response/ArtifactWorkflowRun.cs index 3b34e7cb45..d45d7aae59 100644 --- a/Octokit/Models/Response/ArtifactWorkflowRun.cs +++ b/Octokit/Models/Response/ArtifactWorkflowRun.cs @@ -1,8 +1,27 @@ public class ArtifactWorkflowRun { + /// + /// The workflow run Id + /// public int Id { get; private set; } + + /// + /// The repository Id + /// public int RepositoryId { get; private set; } + + /// + /// The head repository Id + /// public int HeadRepositoryId { get; private set; } + + /// + /// The head branch + /// public string HeadBranch { get; private set; } + + /// + /// The head Sha + /// public string HeadSha { get; private set; } } diff --git a/Octokit/Models/Response/ListArtifactsResponse.cs b/Octokit/Models/Response/ListArtifactsResponse.cs index eac94df351..55dcaa7b43 100644 --- a/Octokit/Models/Response/ListArtifactsResponse.cs +++ b/Octokit/Models/Response/ListArtifactsResponse.cs @@ -2,6 +2,13 @@ public class ListArtifactsResponse { + /// + /// The number of artifacts found + /// public int TotalCount { get; private set; } + + /// + /// The list of found artifacts + /// public IReadOnlyList Artifacts { get; private set; } = new List(); } \ No newline at end of file From 74e1fee0a835ccf708d61e3bc762795ba57d004a Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:38:25 +0100 Subject: [PATCH 04/16] GetRawStream --- Octokit/Clients/ActionsArtifactsClient.cs | 7 ++-- Octokit/Clients/IActionsArtifactsClient.cs | 5 +-- Octokit/Http/ApiConnection.cs | 10 ++++++ Octokit/Http/Connection.cs | 39 +++++++++++++++++++++- Octokit/Http/HttpClientAdapter.cs | 29 ++++++++-------- Octokit/Http/IApiConnection.cs | 10 ++++++ Octokit/Http/IConnection.cs | 10 ++++++ 7 files changed, 89 insertions(+), 21 deletions(-) diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index 6c22e22da5..7465cf32d4 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.IO; +using System.Threading.Tasks; namespace Octokit { @@ -44,14 +45,14 @@ public Task DeleteArtifact(string owner, string repository, int artifactId) return ApiConnection.Delete(ApiUrls.Artifact(owner, repository, artifactId), null); } - public Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + public Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); Ensure.ArgumentNotNullOrDefault(artifactId, nameof(artifactId)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(archiveFormat)); - return ApiConnection.GetRaw(ApiUrls.DownloadArtifact(owner, repository, artifactId, archiveFormat), null); + return ApiConnection.GetRawStream(ApiUrls.DownloadArtifact(owner, repository, artifactId, archiveFormat), null); } public Task ListWorkflowArtifacts(string owner, string repository, int runId) diff --git a/Octokit/Clients/IActionsArtifactsClient.cs b/Octokit/Clients/IActionsArtifactsClient.cs index 0300f8bd8e..6fc17d8c9e 100644 --- a/Octokit/Clients/IActionsArtifactsClient.cs +++ b/Octokit/Clients/IActionsArtifactsClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.IO; +using System.Threading.Tasks; namespace Octokit { @@ -13,7 +14,7 @@ public interface IActionsArtifactsClient Task ListArtifacts(string owner, string repository); Task GetArtifact(string owner, string repository, int artifactId); Task DeleteArtifact(string owner, string repository, int artifactId); - Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); + Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); Task ListWorkflowArtifacts(string owner, string repository, int runId); } } diff --git a/Octokit/Http/ApiConnection.cs b/Octokit/Http/ApiConnection.cs index e590a37ac5..6cb3f5328d 100644 --- a/Octokit/Http/ApiConnection.cs +++ b/Octokit/Http/ApiConnection.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -138,6 +139,15 @@ public async Task GetRaw(Uri uri, IDictionary parameters var response = await Connection.GetRaw(uri, parameters).ConfigureAwait(false); return response.Body; } + + /// + public async Task GetRawStream(Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + var response = await Connection.GetRawStream(uri, parameters).ConfigureAwait(false); + return response.Body; + } /// /// Gets all API resources in the list at the specified URI. diff --git a/Octokit/Http/Connection.cs b/Octokit/Http/Connection.cs index 46eeadcc28..28b5218847 100644 --- a/Octokit/Http/Connection.cs +++ b/Octokit/Http/Connection.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; @@ -241,6 +242,19 @@ public Task> GetRaw(Uri uri, IDictionary pa Endpoint = uri.ApplyParameters(parameters) }); } + + /// + public Task> GetRawStream(Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return GetRawStream(new Request + { + Method = HttpMethod.Get, + BaseAddress = BaseAddress, + Endpoint = uri.ApplyParameters(parameters) + }); + } public Task> Patch(Uri uri, object body) { @@ -686,7 +700,30 @@ async Task> GetRaw(IRequest request) { request.Headers.Add("Accept", AcceptHeaders.RawContentMediaType); var response = await RunRequest(request, CancellationToken.None).ConfigureAwait(false); - return new ApiResponse(response, response.Body as byte[]); + + return new ApiResponse(response, await StreamToByteArray(response.Body as Stream)); + } + + async Task> GetRawStream(IRequest request) + { + request.Headers.Add("Accept", AcceptHeaders.RawContentMediaType); + var response = await RunRequest(request, CancellationToken.None).ConfigureAwait(false); + + return new ApiResponse(response, response.Body as Stream); + } + + async Task StreamToByteArray(Stream stream) + { + if (stream is MemoryStream memoryStream) + { + return memoryStream.ToArray(); + } + + using (var ms = new MemoryStream()) + { + await stream.CopyToAsync(ms); + return ms.ToArray(); + } } async Task> Run(IRequest request, CancellationToken cancellationToken, Func preprocessResponseBody = null) diff --git a/Octokit/Http/HttpClientAdapter.cs b/Octokit/Http/HttpClientAdapter.cs index 6e0b8354d3..0e54074dff 100644 --- a/Octokit/Http/HttpClientAdapter.cs +++ b/Octokit/Http/HttpClientAdapter.cs @@ -83,25 +83,24 @@ protected virtual async Task BuildResponse(HttpResponseMessage respon "application/x-gzip" , "application/octet-stream"}; - using (var content = responseMessage.Content) + var content = responseMessage.Content; + if (content != null) { - if (content != null) - { - contentType = GetContentMediaType(responseMessage.Content); + contentType = GetContentMediaType(content); - if (contentType != null && (contentType.StartsWith("image/") || binaryContentTypes + if (contentType != null && (contentType.StartsWith("image/") || binaryContentTypes .Any(item => item.Equals(contentType, StringComparison.OrdinalIgnoreCase)))) - { - responseBody = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - } - else - { - responseBody = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); - } - - if (!(preprocessResponseBody is null)) - responseBody = preprocessResponseBody(responseBody); + { + responseBody = await content.ReadAsStreamAsync().ConfigureAwait(false); } + else + { + responseBody = await content.ReadAsStringAsync().ConfigureAwait(false); + content.Dispose(); + } + + if (!(preprocessResponseBody is null)) + responseBody = preprocessResponseBody(responseBody); } var responseHeaders = responseMessage.Headers.ToDictionary(h => h.Key, h => h.Value.First()); diff --git a/Octokit/Http/IApiConnection.cs b/Octokit/Http/IApiConnection.cs index d6e60b3985..da4a541f1c 100644 --- a/Octokit/Http/IApiConnection.cs +++ b/Octokit/Http/IApiConnection.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -71,6 +72,15 @@ public interface IApiConnection /// Thrown when an API error occurs. Task GetRaw(Uri uri, IDictionary parameters); + /// + /// Gets the raw stream of the API resource at the specified URI. + /// + /// URI of the API resource to get + /// Parameters to add to the API request + /// The API resource's raw stream or null if the points to a directory. + /// Thrown when an API error occurs. + Task GetRawStream(Uri uri, IDictionary parameters); + /// /// Gets all API resources in the list at the specified URI. /// diff --git a/Octokit/Http/IConnection.cs b/Octokit/Http/IConnection.cs index 2696d8ee4e..8301b64c0d 100644 --- a/Octokit/Http/IConnection.cs +++ b/Octokit/Http/IConnection.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -29,6 +30,15 @@ public interface IConnection : IApiInfoProvider /// representing the received HTTP response /// The property will be null if the points to a directory instead of a file Task> GetRaw(Uri uri, IDictionary parameters); + + /// + /// Performs an asynchronous HTTP GET request that expects a containing raw data. + /// + /// URI endpoint to send request to + /// Querystring parameters for the request + /// representing the received HTTP response + /// The property will be null if the points to a directory instead of a file + Task> GetRawStream(Uri uri, IDictionary parameters); /// /// Performs an asynchronous HTTP GET request. From 4c72b0bdd6fa604643baa93bae27fd075dd54ac5 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:44:53 +0100 Subject: [PATCH 05/16] Fix tests --- Octokit.Tests/Http/HttpClientAdapterTests.cs | 8 +++++--- Octokit/Models/Response/Artifact.cs | 5 +++++ Octokit/Models/Response/ArtifactWorkflowRun.cs | 6 ++++++ Octokit/Models/Response/ListArtifactsResponse.cs | 5 +++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Octokit.Tests/Http/HttpClientAdapterTests.cs b/Octokit.Tests/Http/HttpClientAdapterTests.cs index 6a41c30f68..8d1c570b19 100644 --- a/Octokit.Tests/Http/HttpClientAdapterTests.cs +++ b/Octokit.Tests/Http/HttpClientAdapterTests.cs @@ -143,9 +143,9 @@ public async Task BuildsResponseFromResponseMessage(HttpStatusCode httpStatusCod Assert.Equal(httpStatusCode, response.StatusCode); Assert.Null(response.ContentType); } - + [Fact] - public async Task BuildsByteArrayResponseFromResponseMessage() + public async Task BuildsStreamResponseFromResponseMessage() { var responseMessage = new HttpResponseMessage { @@ -157,7 +157,9 @@ public async Task BuildsByteArrayResponseFromResponseMessage() var response = await tester.BuildResponseTester(responseMessage); - Assert.Equal(new byte[] { 0, 1, 1, 0, 1 }, response.Body); + var memoryStream = Assert.IsType(response.Body); + + Assert.Equal(new byte[] { 0, 1, 1, 0, 1 }, memoryStream.ToArray()); Assert.Equal("image/png", response.ContentType); } diff --git a/Octokit/Models/Response/Artifact.cs b/Octokit/Models/Response/Artifact.cs index a97182be09..b5a6849244 100644 --- a/Octokit/Models/Response/Artifact.cs +++ b/Octokit/Models/Response/Artifact.cs @@ -1,5 +1,8 @@ using System; +using System.Diagnostics; +using System.Globalization; +[DebuggerDisplay("{DebuggerDisplay,nq}")] public class Artifact { /// @@ -56,4 +59,6 @@ public class Artifact /// The workflow from where the artifact was created /// public ArtifactWorkflowRun WorkflowRun { get; private set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "Id: {0}", Id); } \ No newline at end of file diff --git a/Octokit/Models/Response/ArtifactWorkflowRun.cs b/Octokit/Models/Response/ArtifactWorkflowRun.cs index d45d7aae59..242e5a6aab 100644 --- a/Octokit/Models/Response/ArtifactWorkflowRun.cs +++ b/Octokit/Models/Response/ArtifactWorkflowRun.cs @@ -1,3 +1,7 @@ +using System.Diagnostics; +using System.Globalization; + +[DebuggerDisplay("{DebuggerDisplay,nq}")] public class ArtifactWorkflowRun { /// @@ -24,4 +28,6 @@ public class ArtifactWorkflowRun /// The head Sha /// public string HeadSha { get; private set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "Id: {0}", Id); } diff --git a/Octokit/Models/Response/ListArtifactsResponse.cs b/Octokit/Models/Response/ListArtifactsResponse.cs index 55dcaa7b43..b7eb9ecd9a 100644 --- a/Octokit/Models/Response/ListArtifactsResponse.cs +++ b/Octokit/Models/Response/ListArtifactsResponse.cs @@ -1,5 +1,8 @@ using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +[DebuggerDisplay("{DebuggerDisplay,nq}")] public class ListArtifactsResponse { /// @@ -11,4 +14,6 @@ public class ListArtifactsResponse /// The list of found artifacts /// public IReadOnlyList Artifacts { get; private set; } = new List(); + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "Artifacts: {0}", TotalCount); } \ No newline at end of file From 012982a42785cd23858ddebc9372c09a3edb2750 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:50:17 +0100 Subject: [PATCH 06/16] Xml docs --- Octokit/Clients/ActionsArtifactsClient.cs | 10 ++++++ Octokit/Clients/IActionsArtifactsClient.cs | 39 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index 7465cf32d4..309b966cf4 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -19,6 +19,8 @@ public ActionsArtifactsClient(IApiConnection apiConnection) : base(apiConnection { } + /// + [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts")] public Task ListArtifacts(string owner, string repository) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); @@ -27,6 +29,8 @@ public Task ListArtifacts(string owner, string repository return ApiConnection.Get(ApiUrls.ListArtifacts(owner, repository), null); } + /// + [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}")] public Task GetArtifact(string owner, string repository, int artifactId) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); @@ -36,6 +40,8 @@ public Task GetArtifact(string owner, string repository, int artifactI return ApiConnection.Get(ApiUrls.Artifact(owner, repository, artifactId), null); } + /// + [ManualRoute("DELETE", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}")] public Task DeleteArtifact(string owner, string repository, int artifactId) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); @@ -45,6 +51,8 @@ public Task DeleteArtifact(string owner, string repository, int artifactId) return ApiConnection.Delete(ApiUrls.Artifact(owner, repository, artifactId), null); } + /// + [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}/{archive_format}")] public Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); @@ -55,6 +63,8 @@ public Task DownloadArtifact(string owner, string repository, int artifa return ApiConnection.GetRawStream(ApiUrls.DownloadArtifact(owner, repository, artifactId, archiveFormat), null); } + /// + [ManualRoute("GET", "/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts")] public Task ListWorkflowArtifacts(string owner, string repository, int runId) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); diff --git a/Octokit/Clients/IActionsArtifactsClient.cs b/Octokit/Clients/IActionsArtifactsClient.cs index 6fc17d8c9e..e8084bf63b 100644 --- a/Octokit/Clients/IActionsArtifactsClient.cs +++ b/Octokit/Clients/IActionsArtifactsClient.cs @@ -11,10 +11,49 @@ namespace Octokit /// public interface IActionsArtifactsClient { + /// + /// Lists artifacts for a repository + /// + /// + /// + /// Task ListArtifacts(string owner, string repository); + + /// + /// Gets the specified artifact + /// + /// + /// + /// + /// Task GetArtifact(string owner, string repository, int artifactId); + + /// + /// Deletes the specified artifact + /// + /// + /// + /// + /// Task DeleteArtifact(string owner, string repository, int artifactId); + + /// + /// Downloads the specified artifact's contents + /// + /// + /// + /// + /// + /// Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); + + /// + /// Lists the artifacts for a specific workflow run + /// + /// + /// + /// + /// Task ListWorkflowArtifacts(string owner, string repository, int runId); } } From 5487d8441a7a990d53d6e2744404ad47aa0bf47c Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 12:53:33 +0100 Subject: [PATCH 07/16] Default constructors --- Octokit/Models/Response/Artifact.cs | 19 +++++++++++++++++++ .../Models/Response/ArtifactWorkflowRun.cs | 13 +++++++++++++ .../Models/Response/ListArtifactsResponse.cs | 10 ++++++++++ 3 files changed, 42 insertions(+) diff --git a/Octokit/Models/Response/Artifact.cs b/Octokit/Models/Response/Artifact.cs index b5a6849244..a25cc19641 100644 --- a/Octokit/Models/Response/Artifact.cs +++ b/Octokit/Models/Response/Artifact.cs @@ -5,6 +5,25 @@ [DebuggerDisplay("{DebuggerDisplay,nq}")] public class Artifact { + public Artifact() + { + } + + public Artifact(int id, string nodeId, string name, int sizeInBytes, string url, string archiveDownloadUrl, bool expired, DateTime createdAt, DateTime expiresAt, DateTime updatedAt, ArtifactWorkflowRun workflowRun) + { + Id = id; + NodeId = nodeId; + Name = name; + SizeInBytes = sizeInBytes; + Url = url; + ArchiveDownloadUrl = archiveDownloadUrl; + Expired = expired; + CreatedAt = createdAt; + ExpiresAt = expiresAt; + UpdatedAt = updatedAt; + WorkflowRun = workflowRun; + } + /// /// The artifact Id /// diff --git a/Octokit/Models/Response/ArtifactWorkflowRun.cs b/Octokit/Models/Response/ArtifactWorkflowRun.cs index 242e5a6aab..c6acf248ce 100644 --- a/Octokit/Models/Response/ArtifactWorkflowRun.cs +++ b/Octokit/Models/Response/ArtifactWorkflowRun.cs @@ -4,6 +4,19 @@ [DebuggerDisplay("{DebuggerDisplay,nq}")] public class ArtifactWorkflowRun { + public ArtifactWorkflowRun() + { + } + + public ArtifactWorkflowRun(int id, int repositoryId, int headRepositoryId, string headBranch, string headSha) + { + Id = id; + RepositoryId = repositoryId; + HeadRepositoryId = headRepositoryId; + HeadBranch = headBranch; + HeadSha = headSha; + } + /// /// The workflow run Id /// diff --git a/Octokit/Models/Response/ListArtifactsResponse.cs b/Octokit/Models/Response/ListArtifactsResponse.cs index b7eb9ecd9a..0d6a9db2be 100644 --- a/Octokit/Models/Response/ListArtifactsResponse.cs +++ b/Octokit/Models/Response/ListArtifactsResponse.cs @@ -5,6 +5,16 @@ [DebuggerDisplay("{DebuggerDisplay,nq}")] public class ListArtifactsResponse { + public ListArtifactsResponse() + { + } + + public ListArtifactsResponse(int totalCount, IReadOnlyList artifacts) + { + TotalCount = totalCount; + Artifacts = artifacts; + } + /// /// The number of artifacts found /// From 64340352bc35925b9a09eea2bd3bb79acff14dc4 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 13:01:33 +0100 Subject: [PATCH 08/16] ObservableActionsArtifactsClient.cs --- .../IObservableActionsArtifactsClient.cs | 45 ++++++++++++++++++- .../ObservableActionsArtifactsClient.cs | 37 ++++++++++++++- Octokit/Clients/ActionsArtifactsClient.cs | 10 ++--- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs index 38e6a34a9c..902a2cbc5d 100644 --- a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs +++ b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs @@ -1,4 +1,9 @@ -namespace Octokit.Reactive +using System; +using System.IO; +using System.Reactive; +using System.Threading.Tasks; + +namespace Octokit.Reactive { /// /// A client for GitHub's Actions Artifacts API. @@ -8,5 +13,43 @@ /// public interface IObservableActionsArtifactsClient { + IObservable ListArtifacts(string owner, string repository); + + /// + /// Gets the specified artifact + /// + /// + /// + /// + /// + IObservable GetArtifact(string owner, string repository, int artifactId); + + /// + /// Deletes the specified artifact + /// + /// + /// + /// + /// + IObservable DeleteArtifact(string owner, string repository, int artifactId); + + /// + /// Downloads the specified artifact's contents + /// + /// + /// + /// + /// + /// + IObservable DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); + + /// + /// Lists the artifacts for a specific workflow run + /// + /// + /// + /// + /// + IObservable ListWorkflowArtifacts(string owner, string repository, int runId); } } diff --git a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs index 9f152cbd11..077e27077c 100644 --- a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs +++ b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs @@ -1,4 +1,9 @@ -namespace Octokit.Reactive +using System; +using System.IO; +using System.Reactive; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive { public class ObservableActionsArtifactsClient : IObservableActionsArtifactsClient { @@ -14,5 +19,35 @@ public ObservableActionsArtifactsClient(IGitHubClient client) _client = client.Actions.Artifacts; } + + /// + public IObservable ListArtifacts(string owner, string repository) + { + return _client.ListArtifacts(owner, repository).ToObservable(); + } + + /// + public IObservable GetArtifact(string owner, string repository, int artifactId) + { + return _client.GetArtifact(owner, repository, artifactId).ToObservable(); + } + + /// + public IObservable DeleteArtifact(string owner, string repository, int artifactId) + { + return _client.DeleteArtifact(owner, repository, artifactId).ToObservable(); + } + + /// + public IObservable DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + { + return _client.DownloadArtifact(owner, repository, artifactId, archiveFormat).ToObservable(); + } + + /// + public IObservable ListWorkflowArtifacts(string owner, string repository, int runId) + { + return _client.ListWorkflowArtifacts(owner, repository, runId).ToObservable(); + } } } diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index 309b966cf4..2565230fe7 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -19,7 +19,7 @@ public ActionsArtifactsClient(IApiConnection apiConnection) : base(apiConnection { } - /// + /// [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts")] public Task ListArtifacts(string owner, string repository) { @@ -29,7 +29,7 @@ public Task ListArtifacts(string owner, string repository return ApiConnection.Get(ApiUrls.ListArtifacts(owner, repository), null); } - /// + /// [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}")] public Task GetArtifact(string owner, string repository, int artifactId) { @@ -40,7 +40,7 @@ public Task GetArtifact(string owner, string repository, int artifactI return ApiConnection.Get(ApiUrls.Artifact(owner, repository, artifactId), null); } - /// + /// [ManualRoute("DELETE", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}")] public Task DeleteArtifact(string owner, string repository, int artifactId) { @@ -51,7 +51,7 @@ public Task DeleteArtifact(string owner, string repository, int artifactId) return ApiConnection.Delete(ApiUrls.Artifact(owner, repository, artifactId), null); } - /// + /// [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}/{archive_format}")] public Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) { @@ -63,7 +63,7 @@ public Task DownloadArtifact(string owner, string repository, int artifa return ApiConnection.GetRawStream(ApiUrls.DownloadArtifact(owner, repository, artifactId, archiveFormat), null); } - /// + /// [ManualRoute("GET", "/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts")] public Task ListWorkflowArtifacts(string owner, string repository, int runId) { From c6455cae7685d59a9ffc41320d61eecb2439ffd5 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 14:36:15 +0100 Subject: [PATCH 09/16] ListArtifactsRequest --- .../IObservableActionsArtifactsClient.cs | 5 ++- .../ObservableActionsArtifactsClient.cs | 8 ++--- Octokit/Clients/ActionsArtifactsClient.cs | 8 ++--- Octokit/Clients/IActionsArtifactsClient.cs | 4 +-- .../Models/Request/ListArtifactsRequest.cs | 32 +++++++++++++++++++ 5 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 Octokit/Models/Request/ListArtifactsRequest.cs diff --git a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs index 902a2cbc5d..260842c29b 100644 --- a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs +++ b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Reactive; -using System.Threading.Tasks; namespace Octokit.Reactive { @@ -13,7 +12,7 @@ namespace Octokit.Reactive /// public interface IObservableActionsArtifactsClient { - IObservable ListArtifacts(string owner, string repository); + IObservable ListArtifacts(string owner, string repository, ListArtifactsRequest listArtifactsRequest = null); /// /// Gets the specified artifact @@ -50,6 +49,6 @@ public interface IObservableActionsArtifactsClient /// /// /// - IObservable ListWorkflowArtifacts(string owner, string repository, int runId); + IObservable ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null); } } diff --git a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs index 077e27077c..c810fea156 100644 --- a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs +++ b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs @@ -21,9 +21,9 @@ public ObservableActionsArtifactsClient(IGitHubClient client) } /// - public IObservable ListArtifacts(string owner, string repository) + public IObservable ListArtifacts(string owner, string repository, ListArtifactsRequest listArtifactsRequest = null) { - return _client.ListArtifacts(owner, repository).ToObservable(); + return _client.ListArtifacts(owner, repository, listArtifactsRequest).ToObservable(); } /// @@ -45,9 +45,9 @@ public IObservable DownloadArtifact(string owner, string repository, int } /// - public IObservable ListWorkflowArtifacts(string owner, string repository, int runId) + public IObservable ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null) { - return _client.ListWorkflowArtifacts(owner, repository, runId).ToObservable(); + return _client.ListWorkflowArtifacts(owner, repository, runId, listArtifactsRequest).ToObservable(); } } } diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index 2565230fe7..79c664e6d2 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -21,12 +21,12 @@ public ActionsArtifactsClient(IApiConnection apiConnection) : base(apiConnection /// [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts")] - public Task ListArtifacts(string owner, string repository) + public Task ListArtifacts(string owner, string repository, ListArtifactsRequest listArtifactsRequest = null) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); - return ApiConnection.Get(ApiUrls.ListArtifacts(owner, repository), null); + return ApiConnection.Get(ApiUrls.ListArtifacts(owner, repository), listArtifactsRequest?.ToParametersDictionary()); } /// @@ -65,13 +65,13 @@ public Task DownloadArtifact(string owner, string repository, int artifa /// [ManualRoute("GET", "/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts")] - public Task ListWorkflowArtifacts(string owner, string repository, int runId) + public Task ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); Ensure.ArgumentNotNullOrDefault(runId, nameof(runId)); - return ApiConnection.Get(ApiUrls.ListWorkflowArtifacts(owner, repository, runId), null); + return ApiConnection.Get(ApiUrls.ListWorkflowArtifacts(owner, repository, runId), listArtifactsRequest?.ToParametersDictionary()); } } } diff --git a/Octokit/Clients/IActionsArtifactsClient.cs b/Octokit/Clients/IActionsArtifactsClient.cs index e8084bf63b..d132c3bbcd 100644 --- a/Octokit/Clients/IActionsArtifactsClient.cs +++ b/Octokit/Clients/IActionsArtifactsClient.cs @@ -17,7 +17,7 @@ public interface IActionsArtifactsClient /// /// /// - Task ListArtifacts(string owner, string repository); + Task ListArtifacts(string owner, string repository, ListArtifactsRequest listArtifactsRequest = null); /// /// Gets the specified artifact @@ -54,6 +54,6 @@ public interface IActionsArtifactsClient /// /// /// - Task ListWorkflowArtifacts(string owner, string repository, int runId); + Task ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null); } } diff --git a/Octokit/Models/Request/ListArtifactsRequest.cs b/Octokit/Models/Request/ListArtifactsRequest.cs new file mode 100644 index 0000000000..180f183b3e --- /dev/null +++ b/Octokit/Models/Request/ListArtifactsRequest.cs @@ -0,0 +1,32 @@ +using System.Diagnostics; +using System.Globalization; +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Used to filter requests for lists of pull requests. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class ListArtifactsRequest : RequestParameters + { + /// + /// Filter artifacts by name. + /// + public string Name { get; set; } + + /// + /// How many results to return per page (maximum 100). + /// + [Parameter(Key = "per_page")] + public int PerPage { get; set; } = 30; + + /// + /// What page to retrieve. + /// + [Parameter(Key = "page")] + public int Page { get; set; } = 1; + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "Page: {0}, PerPage: {1} ", Page, PerPage); + } +} From 035ce23b708c7d6cc8c38b521ec9ad862929b45f Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 14:38:07 +0100 Subject: [PATCH 10/16] Fix xml doc --- Octokit/Models/Request/ListArtifactsRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit/Models/Request/ListArtifactsRequest.cs b/Octokit/Models/Request/ListArtifactsRequest.cs index 180f183b3e..eaf6095851 100644 --- a/Octokit/Models/Request/ListArtifactsRequest.cs +++ b/Octokit/Models/Request/ListArtifactsRequest.cs @@ -5,7 +5,7 @@ namespace Octokit { /// - /// Used to filter requests for lists of pull requests. + /// Used to filter requests for lists of artifacts. /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public class ListArtifactsRequest : RequestParameters From 4042cbd28879042550497869bd4f17f642c0554d Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Sat, 23 Sep 2023 14:41:46 +0100 Subject: [PATCH 11/16] Simplify inheritdoc --- Octokit/Http/ApiConnection.cs | 2 +- Octokit/Http/Connection.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit/Http/ApiConnection.cs b/Octokit/Http/ApiConnection.cs index 6cb3f5328d..9d729947e9 100644 --- a/Octokit/Http/ApiConnection.cs +++ b/Octokit/Http/ApiConnection.cs @@ -140,7 +140,7 @@ public async Task GetRaw(Uri uri, IDictionary parameters return response.Body; } - /// + /// public async Task GetRawStream(Uri uri, IDictionary parameters) { Ensure.ArgumentNotNull(uri, nameof(uri)); diff --git a/Octokit/Http/Connection.cs b/Octokit/Http/Connection.cs index 28b5218847..c0fc81f4ee 100644 --- a/Octokit/Http/Connection.cs +++ b/Octokit/Http/Connection.cs @@ -243,7 +243,7 @@ public Task> GetRaw(Uri uri, IDictionary pa }); } - /// + /// public Task> GetRawStream(Uri uri, IDictionary parameters) { Ensure.ArgumentNotNull(uri, nameof(uri)); From 0d28fcc1debbaae67560a0133115dd0f16b6fa6b Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:53:39 +0100 Subject: [PATCH 12/16] Longs --- .../Clients/IObservableActionsArtifactsClient.cs | 8 ++++---- .../Clients/ObservableActionsArtifactsClient.cs | 8 ++++---- Octokit/Clients/ActionsArtifactsClient.cs | 8 ++++---- Octokit/Clients/IActionsArtifactsClient.cs | 8 ++++---- Octokit/Helpers/ApiUrls.cs | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs index 260842c29b..7962035272 100644 --- a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs +++ b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs @@ -21,7 +21,7 @@ public interface IObservableActionsArtifactsClient /// /// /// - IObservable GetArtifact(string owner, string repository, int artifactId); + IObservable GetArtifact(string owner, string repository, long artifactId); /// /// Deletes the specified artifact @@ -30,7 +30,7 @@ public interface IObservableActionsArtifactsClient /// /// /// - IObservable DeleteArtifact(string owner, string repository, int artifactId); + IObservable DeleteArtifact(string owner, string repository, long artifactId); /// /// Downloads the specified artifact's contents @@ -40,7 +40,7 @@ public interface IObservableActionsArtifactsClient /// /// /// - IObservable DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); + IObservable DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat); /// /// Lists the artifacts for a specific workflow run @@ -49,6 +49,6 @@ public interface IObservableActionsArtifactsClient /// /// /// - IObservable ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null); + IObservable ListWorkflowArtifacts(string owner, string repository, long runId, ListArtifactsRequest listArtifactsRequest = null); } } diff --git a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs index c810fea156..5358992e32 100644 --- a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs +++ b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs @@ -27,25 +27,25 @@ public IObservable ListArtifacts(string owner, string rep } /// - public IObservable GetArtifact(string owner, string repository, int artifactId) + public IObservable GetArtifact(string owner, string repository, long artifactId) { return _client.GetArtifact(owner, repository, artifactId).ToObservable(); } /// - public IObservable DeleteArtifact(string owner, string repository, int artifactId) + public IObservable DeleteArtifact(string owner, string repository, long artifactId) { return _client.DeleteArtifact(owner, repository, artifactId).ToObservable(); } /// - public IObservable DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + public IObservable DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat) { return _client.DownloadArtifact(owner, repository, artifactId, archiveFormat).ToObservable(); } /// - public IObservable ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null) + public IObservable ListWorkflowArtifacts(string owner, string repository, long runId, ListArtifactsRequest listArtifactsRequest = null) { return _client.ListWorkflowArtifacts(owner, repository, runId, listArtifactsRequest).ToObservable(); } diff --git a/Octokit/Clients/ActionsArtifactsClient.cs b/Octokit/Clients/ActionsArtifactsClient.cs index 79c664e6d2..96f8967d42 100644 --- a/Octokit/Clients/ActionsArtifactsClient.cs +++ b/Octokit/Clients/ActionsArtifactsClient.cs @@ -31,7 +31,7 @@ public Task ListArtifacts(string owner, string repository /// [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}")] - public Task GetArtifact(string owner, string repository, int artifactId) + public Task GetArtifact(string owner, string repository, long artifactId) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); @@ -42,7 +42,7 @@ public Task GetArtifact(string owner, string repository, int artifactI /// [ManualRoute("DELETE", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}")] - public Task DeleteArtifact(string owner, string repository, int artifactId) + public Task DeleteArtifact(string owner, string repository, long artifactId) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); @@ -53,7 +53,7 @@ public Task DeleteArtifact(string owner, string repository, int artifactId) /// [ManualRoute("GET", "/repos/{owner}/{repository}/actions/artifacts/{artifact_id}/{archive_format}")] - public Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + public Task DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); @@ -65,7 +65,7 @@ public Task DownloadArtifact(string owner, string repository, int artifa /// [ManualRoute("GET", "/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts")] - public Task ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null) + public Task ListWorkflowArtifacts(string owner, string repository, long runId, ListArtifactsRequest listArtifactsRequest = null) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repository, nameof(repository)); diff --git a/Octokit/Clients/IActionsArtifactsClient.cs b/Octokit/Clients/IActionsArtifactsClient.cs index d132c3bbcd..1ce86f2c94 100644 --- a/Octokit/Clients/IActionsArtifactsClient.cs +++ b/Octokit/Clients/IActionsArtifactsClient.cs @@ -26,7 +26,7 @@ public interface IActionsArtifactsClient /// /// /// - Task GetArtifact(string owner, string repository, int artifactId); + Task GetArtifact(string owner, string repository, long artifactId); /// /// Deletes the specified artifact @@ -35,7 +35,7 @@ public interface IActionsArtifactsClient /// /// /// - Task DeleteArtifact(string owner, string repository, int artifactId); + Task DeleteArtifact(string owner, string repository, long artifactId); /// /// Downloads the specified artifact's contents @@ -45,7 +45,7 @@ public interface IActionsArtifactsClient /// /// /// - Task DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat); + Task DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat); /// /// Lists the artifacts for a specific workflow run @@ -54,6 +54,6 @@ public interface IActionsArtifactsClient /// /// /// - Task ListWorkflowArtifacts(string owner, string repository, int runId, ListArtifactsRequest listArtifactsRequest = null); + Task ListWorkflowArtifacts(string owner, string repository, long runId, ListArtifactsRequest listArtifactsRequest = null); } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index bf467fbf65..caffbb1668 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -5491,7 +5491,7 @@ public static Uri ListArtifacts(string owner, string repository) /// The name of the repository /// The id of the artifact /// - public static Uri Artifact(string owner, string repository, int artifactId) + public static Uri Artifact(string owner, string repository, long artifactId) { return "repos/{0}/{1}/actions/artifacts/{2}".FormatUri(owner, repository, artifactId); } @@ -5503,7 +5503,7 @@ public static Uri Artifact(string owner, string repository, int artifactId) /// The name of the repository /// The id of the artifact /// - public static Uri DownloadArtifact(string owner, string repository, int artifactId, string archiveFormat) + public static Uri DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat) { return "repos/{0}/{1}/actions/artifacts/{2}/{3}".FormatUri(owner, repository, artifactId); } @@ -5515,7 +5515,7 @@ public static Uri DownloadArtifact(string owner, string repository, int artifact /// The name of the repository /// The id of the workflow run /// - public static Uri ListWorkflowArtifacts(string owner, string repository, int runId) + public static Uri ListWorkflowArtifacts(string owner, string repository, long runId) { return "repos/{0}/{1}/actions/runs/{2}/artifacts".FormatUri(owner, repository, runId); } From 7e042fbfd4ae1ad04c93dbaf916c69825732ab89 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:55:28 +0100 Subject: [PATCH 13/16] Longs --- Octokit/Models/Response/Artifact.cs | 4 ++-- Octokit/Models/Response/ArtifactWorkflowRun.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Octokit/Models/Response/Artifact.cs b/Octokit/Models/Response/Artifact.cs index a25cc19641..1f6be53771 100644 --- a/Octokit/Models/Response/Artifact.cs +++ b/Octokit/Models/Response/Artifact.cs @@ -9,7 +9,7 @@ public Artifact() { } - public Artifact(int id, string nodeId, string name, int sizeInBytes, string url, string archiveDownloadUrl, bool expired, DateTime createdAt, DateTime expiresAt, DateTime updatedAt, ArtifactWorkflowRun workflowRun) + public Artifact(long id, string nodeId, string name, int sizeInBytes, string url, string archiveDownloadUrl, bool expired, DateTime createdAt, DateTime expiresAt, DateTime updatedAt, ArtifactWorkflowRun workflowRun) { Id = id; NodeId = nodeId; @@ -27,7 +27,7 @@ public Artifact(int id, string nodeId, string name, int sizeInBytes, string url, /// /// The artifact Id /// - public int Id { get; private set; } + public long Id { get; private set; } /// /// The artifact node Id diff --git a/Octokit/Models/Response/ArtifactWorkflowRun.cs b/Octokit/Models/Response/ArtifactWorkflowRun.cs index c6acf248ce..a39a1b6a34 100644 --- a/Octokit/Models/Response/ArtifactWorkflowRun.cs +++ b/Octokit/Models/Response/ArtifactWorkflowRun.cs @@ -8,7 +8,7 @@ public ArtifactWorkflowRun() { } - public ArtifactWorkflowRun(int id, int repositoryId, int headRepositoryId, string headBranch, string headSha) + public ArtifactWorkflowRun(long id, long repositoryId, long headRepositoryId, string headBranch, string headSha) { Id = id; RepositoryId = repositoryId; @@ -20,17 +20,17 @@ public ArtifactWorkflowRun(int id, int repositoryId, int headRepositoryId, strin /// /// The workflow run Id /// - public int Id { get; private set; } + public long Id { get; private set; } /// /// The repository Id /// - public int RepositoryId { get; private set; } + public long RepositoryId { get; private set; } /// /// The head repository Id /// - public int HeadRepositoryId { get; private set; } + public long HeadRepositoryId { get; private set; } /// /// The head branch From 79ec3569eb9954a973b02e269fa44bd1905d5c4a Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:58:46 +0100 Subject: [PATCH 14/16] Missed archive format --- Octokit/Helpers/ApiUrls.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index caffbb1668..8c0746fa0c 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -5505,7 +5505,7 @@ public static Uri Artifact(string owner, string repository, long artifactId) /// public static Uri DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat) { - return "repos/{0}/{1}/actions/artifacts/{2}/{3}".FormatUri(owner, repository, artifactId); + return "repos/{0}/{1}/actions/artifacts/{2}/{3}".FormatUri(owner, repository, artifactId, archiveFormat); } /// From 5349d3b3baa4d0fd6e4dffa8ed30253ccf7ff0f0 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:59:25 +0100 Subject: [PATCH 15/16] XML Comment --- Octokit/Helpers/ApiUrls.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 8c0746fa0c..62ea8140a0 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -5495,13 +5495,14 @@ public static Uri Artifact(string owner, string repository, long artifactId) { return "repos/{0}/{1}/actions/artifacts/{2}".FormatUri(owner, repository, artifactId); } - + /// /// Returns the to download the specified artifact. /// /// The owner of the repository /// The name of the repository /// The id of the artifact + /// The archive format e.g. zip /// public static Uri DownloadArtifact(string owner, string repository, long artifactId, string archiveFormat) { From fc66268b6f56cbbffd893e42ac9adb2669d24db5 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Mon, 25 Sep 2023 19:14:46 +0100 Subject: [PATCH 16/16] Update response docs --- Octokit/Caching/CachedResponse.cs | 4 +--- Octokit/Http/IResponse.cs | 2 +- Octokit/Http/Response.cs | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Octokit/Caching/CachedResponse.cs b/Octokit/Caching/CachedResponse.cs index 4d63371aff..0b2328de96 100644 --- a/Octokit/Caching/CachedResponse.cs +++ b/Octokit/Caching/CachedResponse.cs @@ -28,9 +28,7 @@ public V1(object body, IReadOnlyDictionary headers, ApiInfo apiI ContentType = contentType; } - /// - /// Raw response body. Typically a string, but when requesting images, it will be a byte array. - /// + /// public object Body { get; private set; } /// /// Information about the API. diff --git a/Octokit/Http/IResponse.cs b/Octokit/Http/IResponse.cs index fc10d83630..716d62c08a 100644 --- a/Octokit/Http/IResponse.cs +++ b/Octokit/Http/IResponse.cs @@ -25,7 +25,7 @@ public interface IApiResponse public interface IResponse { /// - /// Raw response body. Typically a string, but when requesting images, it will be a byte array. + /// Raw response body. Typically a string, but when requesting images, or binary files, it will be a Stream. /// object Body { get; } diff --git a/Octokit/Http/Response.cs b/Octokit/Http/Response.cs index 49c99912db..541d6d8281 100644 --- a/Octokit/Http/Response.cs +++ b/Octokit/Http/Response.cs @@ -35,9 +35,7 @@ public Response(HttpStatusCode statusCode, object body, IDictionary - /// Raw response body. Typically a string, but when requesting images, it will be a byte array. - /// + /// public object Body { get; private set; } /// /// Information about the API.