diff --git a/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs
new file mode 100644
index 0000000000..38e6a34a9c
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsArtifactsClient.cs
@@ -0,0 +1,12 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Artifacts API.
+ ///
+ ///
+ /// See the Actions Artifacts API documentation for more information.
+ ///
+ public interface IObservableActionsArtifactsClient
+ {
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsCacheClient.cs b/Octokit.Reactive/Clients/IObservableActionsCacheClient.cs
new file mode 100644
index 0000000000..29f800c427
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsCacheClient.cs
@@ -0,0 +1,12 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Cache API.
+ ///
+ ///
+ /// See the Actions Cache API documentation for more information.
+ ///
+ public interface IObservableActionsCacheClient
+ {
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsClient.cs b/Octokit.Reactive/Clients/IObservableActionsClient.cs
new file mode 100644
index 0000000000..5397fd80e5
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsClient.cs
@@ -0,0 +1,41 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions API.
+ ///
+ ///
+ /// See the Actions API documentation for more information.
+ ///
+ public interface IObservableActionsClient
+ {
+ ///
+ /// Client for the Artifacts API.
+ ///
+ IObservableActionsArtifactsClient Artifacts { get; }
+
+ ///
+ /// Client for the Cache API.
+ ///
+ IObservableActionsCacheClient Cache { get; }
+
+ ///
+ /// Client for the Permissions API.
+ ///
+ IObservableActionsPermissionsClient Permissions { get; }
+
+ ///
+ /// Client for the Self-hosted runner groups API.
+ ///
+ IObservableActionsSelfHostedRunnerGroupsClient SelfHostedRunnerGroups { get; }
+
+ ///
+ /// Client for the Self-hosted runners API.
+ ///
+ IObservableActionsSelfHostedRunnersClient SelfHostedRunners { get; }
+
+ ///
+ /// Client for the Workflows API.
+ ///
+ IObservableActionsWorkflowsClient Workflows { get; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsPermissionsClient.cs b/Octokit.Reactive/Clients/IObservableActionsPermissionsClient.cs
new file mode 100644
index 0000000000..ea3391b0b0
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsPermissionsClient.cs
@@ -0,0 +1,12 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Permissions API.
+ ///
+ ///
+ /// See the Actions Permissions API documentation for more information.
+ ///
+ public interface IObservableActionsPermissionsClient
+ {
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsSelfHostedRunnerGroupsClient.cs b/Octokit.Reactive/Clients/IObservableActionsSelfHostedRunnerGroupsClient.cs
new file mode 100644
index 0000000000..f8e82dc707
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsSelfHostedRunnerGroupsClient.cs
@@ -0,0 +1,12 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Self-hosted runner groups API.
+ ///
+ ///
+ /// See the Actions Self-hosted runner groups API documentation for more information.
+ ///
+ public interface IObservableActionsSelfHostedRunnerGroupsClient
+ {
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsSelfHostedRunnersClient.cs b/Octokit.Reactive/Clients/IObservableActionsSelfHostedRunnersClient.cs
new file mode 100644
index 0000000000..52ef545712
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsSelfHostedRunnersClient.cs
@@ -0,0 +1,12 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Self-hosted runners API.
+ ///
+ ///
+ /// See the Actions Self-hosted runners API documentation for more information.
+ ///
+ public interface IObservableActionsSelfHostedRunnersClient
+ {
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsWorkflowJobsClient.cs b/Octokit.Reactive/Clients/IObservableActionsWorkflowJobsClient.cs
new file mode 100644
index 0000000000..4b1362b0dc
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsWorkflowJobsClient.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Reactive;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Workflows jobs API.
+ ///
+ ///
+ /// See the Actions Workflows jobs API documentation for more information.
+ ///
+ public interface IObservableActionsWorkflowJobsClient
+ {
+ ///
+ /// Re-runs a specific workflow job in a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#re-run-a-job-from-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow job.
+ IObservable Rerun(string owner, string name, long jobId);
+
+ ///
+ /// Gets a specific job in a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-jobs/#get-a-job-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The unique identifier of the job.
+ IObservable Get(string owner, string name, long jobId);
+
+ ///
+ /// Gets the plain text log file for a workflow job.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-jobs/#download-job-logs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow job.
+ IObservable GetLogs(string owner, string name, long jobId);
+
+ ///
+ /// Lists jobs for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable List(string owner, string name, long runId);
+
+ ///
+ /// Lists jobs for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// Details to filter the request, such as by when completed.
+ IObservable List(string owner, string name, long runId, WorkflowRunJobsRequest workflowRunJobsRequest);
+
+ ///
+ /// Lists jobs for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// Details to filter the request, such as by when completed.
+ /// Options to change the API response.
+ IObservable List(string owner, string name, long runId, WorkflowRunJobsRequest workflowRunJobsRequest, ApiOptions options);
+
+ ///
+ /// Lists jobs for a specific workflow run attempt.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run-attempt
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ IObservable List(string owner, string name, long runId, int attemptNumber);
+
+ ///
+ /// Lists jobs for a specific workflow run attempt.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run-attempt
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ /// Options to change the API response.
+ IObservable List(string owner, string name, long runId, int attemptNumber, ApiOptions options);
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsWorkflowRunsClient.cs b/Octokit.Reactive/Clients/IObservableActionsWorkflowRunsClient.cs
new file mode 100644
index 0000000000..968138fe8e
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsWorkflowRunsClient.cs
@@ -0,0 +1,265 @@
+using System;
+using System.Reactive;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Workflows runs API.
+ ///
+ ///
+ /// See the Actions Workflows runs API documentation for more information.
+ ///
+ public interface IObservableActionsWorkflowRunsClient
+ {
+ ///
+ /// Lists all workflow runs for a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-repository
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ IObservable List(string owner, string name);
+
+ ///
+ /// Lists all workflow runs for a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-repository
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// Details to filter the request, such as by check suite Id.
+ IObservable List(string owner, string name, WorkflowRunsRequest workflowRunsRequest);
+
+ ///
+ /// Lists all workflow runs for a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-repository
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// Details to filter the request, such as by check suite Id.
+ /// Options to change the API response.
+ IObservable List(string owner, string name, WorkflowRunsRequest workflowRunsRequest, ApiOptions options);
+
+ ///
+ /// Gets a specific workflow run in a repository. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable Get(string owner, string name, long runId);
+
+ ///
+ /// Deletes a specific workflow run. Anyone with write access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#delete-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable Delete(string owner, string name, long runId);
+
+ ///
+ /// Get the review history for a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-the-review-history-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable GetReviewHistory(string owner, string name, long runId);
+
+ ///
+ /// Approves a workflow run for a pull request from a public fork of a first time contributor.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#approve-a-workflow-run-for-a-fork-pull-request
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable Approve(string owner, string name, long runId);
+
+ ///
+ /// Gets a specific workflow run attempt. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-a-workflow-run-attempt
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ IObservable GetAttempt(string owner, string name, long runId, long attemptNumber);
+
+ ///
+ /// Gets a byte array containing an archive of log files for a specific workflow run attempt.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#download-workflow-run-attempt-logs
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ IObservable GetAttemptLogs(string owner, string name, long runId, long attemptNumber);
+
+ ///
+ /// Cancels a workflow run using its Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#cancel-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable Cancel(string owner, string name, long runId);
+
+ ///
+ /// Gets a byte array containing an archive of log files for a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#download-workflow-run-logs
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable GetLogs(string owner, string name, long runId);
+
+ ///
+ /// Deletes all logs for a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#delete-workflow-run-logs
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable DeleteLogs(string owner, string name, long runId);
+
+ ///
+ /// Approve or reject pending deployments that are waiting on approval by a required reviewer.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#review-pending-deployments-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The review for the pending deployment.
+ IObservable ReviewPendingDeployments(string owner, string name, long runId, PendingDeploymentReview review);
+
+ ///
+ /// Re-runs a specific workflow run in a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#re-run-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable Rerun(string owner, string name, long runId);
+
+ ///
+ /// Re-run all of the failed jobs and their dependent jobs in a workflow run using the Id of the workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#re-run-failed-jobs-from-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable RerunFailedJobs(string owner, string name, long runId);
+
+ ///
+ /// Gets the number of billable minutes and total run time for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-workflow-run-usage
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ IObservable GetUsage(string owner, string name, long runId);
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ IObservable ListByWorkflow(string owner, string name, long workflowId);
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ IObservable ListByWorkflow(string owner, string name, string workflowFileName);
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ /// Details to filter the request, such as by check suite Id.
+ IObservable ListByWorkflow(string owner, string name, long workflowId, WorkflowRunsRequest workflowRunsRequest);
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ /// Details to filter the request, such as by check suite Id.
+ IObservable ListByWorkflow(string owner, string name, string workflowFileName, WorkflowRunsRequest workflowRunsRequest);
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ /// Details to filter the request, such as by check suite Id.
+ /// Options to change the API response.
+ IObservable ListByWorkflow(string owner, string name, long workflowId, WorkflowRunsRequest workflowRunsRequest, ApiOptions options);
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ /// Details to filter the request, such as by check suite Id.
+ /// Options to change the API response.
+ IObservable ListByWorkflow(string owner, string name, string workflowFileName, WorkflowRunsRequest workflowRunsRequest, ApiOptions options);
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableActionsWorkflowsClient.cs b/Octokit.Reactive/Clients/IObservableActionsWorkflowsClient.cs
new file mode 100644
index 0000000000..9c5f055bbc
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableActionsWorkflowsClient.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Reactive;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Workflows API.
+ ///
+ ///
+ /// See the Actions Workflows API documentation for more information.
+ ///
+ public interface IObservableActionsWorkflowsClient
+ {
+ ///
+ /// Manually triggers a GitHub Actions workflow run in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#create-a-workflow-dispatch-event
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ /// The parameters to use to trigger the workflow run.
+ IObservable CreateDispatch(string owner, string name, string workflowFileName, CreateWorkflowDispatch createDispatch);
+
+ ///
+ /// Manually triggers a GitHub Actions workflow run in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#create-a-workflow-dispatch-event
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ /// The parameters to use to trigger the workflow run.
+ IObservable CreateDispatch(string owner, string name, long workflowId, CreateWorkflowDispatch createDispatch);
+
+ ///
+ /// Disables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#disable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ IObservable Disable(string owner, string name, string workflowFileName);
+
+ ///
+ /// Disables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#disable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ IObservable Disable(string owner, string name, long workflowId);
+
+ ///
+ /// Enables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#enable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ IObservable Enable(string owner, string name, string workflowFileName);
+
+ ///
+ /// Enables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#enable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ IObservable Enable(string owner, string name, long workflowId);
+
+ ///
+ /// Gets a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ IObservable Get(string owner, string name, string workflowFileName);
+
+ ///
+ /// Gets a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ IObservable Get(string owner, string name, long workflowId);
+
+ ///
+ /// Gets useage of a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-workflow-usage
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ IObservable GetUsage(string owner, string name, string workflowFileName);
+
+ ///
+ /// Gets useage of a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-workflow-usage
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ IObservable GetUsage(string owner, string name, long workflowId);
+
+ ///
+ /// Lists the workflows in a repository. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#list-repository-workflows
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ IObservable List(string owner, string name);
+
+ ///
+ /// Lists the workflows in a repository. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#list-repository-workflows
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// Options to change the API response.
+ IObservable List(string owner, string name, ApiOptions options);
+
+ ///
+ /// Client for the Workflow jobs API.
+ ///
+ IObservableActionsWorkflowJobsClient Jobs { get; }
+
+ ///
+ /// Client for the Workflow runs API.
+ ///
+ IObservableActionsWorkflowRunsClient Runs { get; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs
new file mode 100644
index 0000000000..9f152cbd11
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsArtifactsClient.cs
@@ -0,0 +1,18 @@
+namespace Octokit.Reactive
+{
+ public class ObservableActionsArtifactsClient : IObservableActionsArtifactsClient
+ {
+ readonly IActionsArtifactsClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Artifacts API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsArtifactsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.Artifacts;
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsCacheClient.cs b/Octokit.Reactive/Clients/ObservableActionsCacheClient.cs
new file mode 100644
index 0000000000..cefea4b59a
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsCacheClient.cs
@@ -0,0 +1,18 @@
+namespace Octokit.Reactive
+{
+ public class ObservableActionsCacheClient : IObservableActionsCacheClient
+ {
+ readonly IActionsCacheClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Cache API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsCacheClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.Cache;
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsClient.cs b/Octokit.Reactive/Clients/ObservableActionsClient.cs
new file mode 100644
index 0000000000..3b0e44620a
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsClient.cs
@@ -0,0 +1,57 @@
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions API.
+ ///
+ ///
+ /// See the Actions API documentation for more information.
+ ///
+ public class ObservableActionsClient : IObservableActionsClient
+ {
+ ///
+ /// Instantiate a new GitHub Actions API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ Artifacts = new ObservableActionsArtifactsClient(client);
+ Cache = new ObservableActionsCacheClient(client);
+ Permissions = new ObservableActionsPermissionsClient(client);
+ SelfHostedRunnerGroups = new ObservableActionsSelfHostedRunnerGroupsClient(client);
+ SelfHostedRunners = new ObservableActionsSelfHostedRunnersClient(client);
+ Workflows = new ObservableActionsWorkflowsClient(client);
+ }
+
+ ///
+ /// Client for the Artifacts API.
+ ///
+ public IObservableActionsArtifactsClient Artifacts { get; private set; }
+
+ ///
+ /// Client for the Cache API.
+ ///
+ public IObservableActionsCacheClient Cache { get; private set; }
+
+ ///
+ /// Client for the Permissions API.
+ ///
+ public IObservableActionsPermissionsClient Permissions { get; private set; }
+
+ ///
+ /// Client for the Self-hosted runner groups API.
+ ///
+ public IObservableActionsSelfHostedRunnerGroupsClient SelfHostedRunnerGroups { get; private set; }
+
+ ///
+ /// Client for the Self-hosted runners API.
+ ///
+ public IObservableActionsSelfHostedRunnersClient SelfHostedRunners { get; private set; }
+
+ ///
+ /// Client for the Workflows API.
+ ///
+ public IObservableActionsWorkflowsClient Workflows { get; private set; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsPermissionsClient.cs b/Octokit.Reactive/Clients/ObservableActionsPermissionsClient.cs
new file mode 100644
index 0000000000..50bbec5947
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsPermissionsClient.cs
@@ -0,0 +1,18 @@
+namespace Octokit.Reactive
+{
+ public class ObservableActionsPermissionsClient : IObservableActionsPermissionsClient
+ {
+ readonly IActionsPermissionsClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Permissions API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsPermissionsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.Permissions;
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsSelfHostedRunnerGroupsClient.cs b/Octokit.Reactive/Clients/ObservableActionsSelfHostedRunnerGroupsClient.cs
new file mode 100644
index 0000000000..e94e6a38b7
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsSelfHostedRunnerGroupsClient.cs
@@ -0,0 +1,18 @@
+namespace Octokit.Reactive
+{
+ public class ObservableActionsSelfHostedRunnerGroupsClient : IObservableActionsSelfHostedRunnerGroupsClient
+ {
+ readonly IActionsSelfHostedRunnerGroupsClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Self-hosted runner groups API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsSelfHostedRunnerGroupsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.SelfHostedRunnerGroups;
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsSelfHostedRunnersClient.cs b/Octokit.Reactive/Clients/ObservableActionsSelfHostedRunnersClient.cs
new file mode 100644
index 0000000000..052b6f90cb
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsSelfHostedRunnersClient.cs
@@ -0,0 +1,18 @@
+namespace Octokit.Reactive
+{
+ public class ObservableActionsSelfHostedRunnersClient : IObservableActionsSelfHostedRunnersClient
+ {
+ readonly IActionsSelfHostedRunnersClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Self-hosted runners API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsSelfHostedRunnersClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.SelfHostedRunners;
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsWorkflowJobsClient.cs b/Octokit.Reactive/Clients/ObservableActionsWorkflowJobsClient.cs
new file mode 100644
index 0000000000..0d8da048e1
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsWorkflowJobsClient.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Reactive;
+using System.Reactive.Threading.Tasks;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Workflow jobs API.
+ ///
+ ///
+ /// See the Actions Workflow jobs API documentation for more information.
+ ///
+ public class ObservableActionsWorkflowJobsClient : IObservableActionsWorkflowJobsClient
+ {
+ readonly IActionsWorkflowJobsClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Workflows jobs API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsWorkflowJobsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.Workflows.Jobs;
+ }
+
+ ///
+ /// Re-runs a specific workflow job in a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#re-run-a-job-from-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow job.
+ public IObservable Rerun(string owner, string name, long jobId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Rerun(owner, name, jobId).ToObservable();
+ }
+
+ ///
+ /// Gets a specific job in a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-jobs/#get-a-job-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The unique identifier of the job.
+ public IObservable Get(string owner, string name, long jobId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Get(owner, name, jobId).ToObservable();
+ }
+
+ ///
+ /// Gets the plain text log file for a workflow job.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-jobs/#download-job-logs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow job.
+ public IObservable GetLogs(string owner, string name, long jobId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.GetLogs(owner, name, jobId).ToObservable();
+ }
+
+ ///
+ /// Lists jobs for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable List(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.List(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Lists jobs for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// Details to filter the request, such as by when completed.
+ public IObservable List(string owner, string name, long runId, WorkflowRunJobsRequest workflowRunJobsRequest)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(workflowRunJobsRequest, nameof(workflowRunJobsRequest));
+
+ return _client.List(owner, name, runId, workflowRunJobsRequest).ToObservable();
+ }
+
+ ///
+ /// Lists jobs for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// Details to filter the request, such as by when completed.
+ /// Options to change the API response.
+ public IObservable List(string owner, string name, long runId, WorkflowRunJobsRequest workflowRunJobsRequest, ApiOptions options)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(workflowRunJobsRequest, nameof(workflowRunJobsRequest));
+
+ return _client.List(owner, name, runId, workflowRunJobsRequest, options).ToObservable();
+ }
+
+ ///
+ /// Lists jobs for a specific workflow run attempt.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run-attempt
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ public IObservable List(string owner, string name, long runId, int attemptNumber)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.List(owner, name, runId, attemptNumber).ToObservable();
+ }
+
+ ///
+ /// Lists jobs for a specific workflow run attempt.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-jobs-for-a-workflow-run-attempt
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ /// Options to change the API response.
+ public IObservable List(string owner, string name, long runId, int attemptNumber, ApiOptions options)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.List(owner, name, runId, attemptNumber, options).ToObservable();
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsWorkflowRunsClient.cs b/Octokit.Reactive/Clients/ObservableActionsWorkflowRunsClient.cs
new file mode 100644
index 0000000000..59fe32017a
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsWorkflowRunsClient.cs
@@ -0,0 +1,427 @@
+using System;
+using System.Reactive;
+using System.Reactive.Threading.Tasks;
+using Octokit.Reactive.Internal;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Actions Workflow runs API.
+ ///
+ ///
+ /// See the Actions Workflow runs API documentation for more information.
+ ///
+ public class ObservableActionsWorkflowRunsClient : IObservableActionsWorkflowRunsClient
+ {
+ readonly IActionsWorkflowRunsClient _client;
+ readonly IConnection _connection;
+
+ ///
+ /// Instantiate a new GitHub Actions Workflows runs API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsWorkflowRunsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.Workflows.Runs;
+ _connection = client.Connection;
+ }
+
+ ///
+ /// Lists all workflow runs for a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-repository
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ public IObservable List(string owner, string name)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.List(owner, name).ToObservable();
+ }
+
+ ///
+ /// Lists all workflow runs for a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-repository
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// Details to filter the request, such as by check suite Id.
+ public IObservable List(string owner, string name, WorkflowRunsRequest workflowRunsRequest)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(workflowRunsRequest, nameof(workflowRunsRequest));
+
+ return _client.List(owner, name, workflowRunsRequest).ToObservable();
+ }
+
+ ///
+ /// Lists all workflow runs for a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-repository
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// Details to filter the request, such as by check suite Id.
+ /// Options to change the API response.
+ public IObservable List(string owner, string name, WorkflowRunsRequest workflowRunsRequest, ApiOptions options)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(workflowRunsRequest, nameof(workflowRunsRequest));
+ Ensure.ArgumentNotNull(options, nameof(options));
+
+ return _client.List(owner, name, workflowRunsRequest, options).ToObservable();
+ }
+
+ ///
+ /// Gets a specific workflow run in a repository. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable Get(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Get(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Deletes a specific workflow run. Anyone with write access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#delete-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable Delete(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Delete(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Get the review history for a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-the-review-history-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable GetReviewHistory(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _connection.GetAndFlattenAllPages(ApiUrls.ActionsWorkflowRunApprovals(owner, name, runId));
+ }
+
+ ///
+ /// Approves a workflow run for a pull request from a public fork of a first time contributor.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#approve-a-workflow-run-for-a-fork-pull-request
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable Approve(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Approve(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Gets a specific workflow run attempt. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-a-workflow-run-attempt
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ public IObservable GetAttempt(string owner, string name, long runId, long attemptNumber)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.GetAttempt(owner, name, runId, attemptNumber).ToObservable();
+ }
+
+ ///
+ /// Gets a byte array containing an archive of log files for a specific workflow run attempt.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#download-workflow-run-attempt-logs
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The attempt number of the workflow run.
+ public IObservable GetAttemptLogs(string owner, string name, long runId, long attemptNumber)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.GetAttemptLogs(owner, name, runId, attemptNumber).ToObservable();
+ }
+
+ ///
+ /// Cancels a workflow run using its Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#cancel-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable Cancel(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Cancel(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Gets a byte array containing an archive of log files for a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#download-workflow-run-logs
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable GetLogs(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.GetLogs(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Deletes all logs for a workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#delete-workflow-run-logs
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable DeleteLogs(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.DeleteLogs(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Approve or reject pending deployments that are waiting on approval by a required reviewer.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#review-pending-deployments-for-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ /// The review for the pending deployment.
+ public IObservable ReviewPendingDeployments(string owner, string name, long runId, PendingDeploymentReview review)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(review, nameof(review));
+
+ return _client.ReviewPendingDeployments(owner, name, runId, review).ToObservable();
+ }
+
+ ///
+ /// Re-runs a specific workflow run in a repository.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#re-run-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable Rerun(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Rerun(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Re-run all of the failed jobs and their dependent jobs in a workflow run using the Id of the workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#re-run-failed-jobs-from-a-workflow-run
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable RerunFailedJobs(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.RerunFailedJobs(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// Gets the number of billable minutes and total run time for a specific workflow run.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#get-workflow-run-usage
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow run.
+ public IObservable GetUsage(string owner, string name, long runId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.GetUsage(owner, name, runId).ToObservable();
+ }
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ public IObservable ListByWorkflow(string owner, string name, long workflowId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.ListByWorkflow(owner, name, workflowId).ToObservable();
+ }
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ /// Details to filter the request, such as by check suite Id.
+ public IObservable ListByWorkflow(string owner, string name, long workflowId, WorkflowRunsRequest workflowRunsRequest)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(workflowRunsRequest, nameof(workflowRunsRequest));
+
+ return _client.ListByWorkflow(owner, name, workflowId, workflowRunsRequest).ToObservable();
+ }
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ /// Details to filter the request, such as by check suite Id.
+ /// Options to change the API response.
+ public IObservable ListByWorkflow(string owner, string name, long workflowId, WorkflowRunsRequest workflowRunsRequest, ApiOptions options)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(workflowRunsRequest, nameof(workflowRunsRequest));
+ Ensure.ArgumentNotNull(options, nameof(options));
+
+ return _client.ListByWorkflow(owner, name, workflowId, workflowRunsRequest, options).ToObservable();
+ }
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ public IObservable ListByWorkflow(string owner, string name, string workflowFileName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+
+ return _client.ListByWorkflow(owner, name, workflowFileName).ToObservable();
+ }
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ /// Details to filter the request, such as by check suite Id.
+ public IObservable ListByWorkflow(string owner, string name, string workflowFileName, WorkflowRunsRequest workflowRunsRequest)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+ Ensure.ArgumentNotNull(workflowRunsRequest, nameof(workflowRunsRequest));
+
+ return _client.ListByWorkflow(owner, name, workflowFileName, workflowRunsRequest).ToObservable();
+ }
+
+ ///
+ /// List all workflow runs for a workflow.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs-for-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ /// Details to filter the request, such as by check suite Id.
+ /// Options to change the API response.
+ public IObservable ListByWorkflow(string owner, string name, string workflowFileName, WorkflowRunsRequest workflowRunsRequest, ApiOptions options)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+ Ensure.ArgumentNotNull(workflowRunsRequest, nameof(workflowRunsRequest));
+ Ensure.ArgumentNotNull(options, nameof(options));
+
+ return _client.ListByWorkflow(owner, name, workflowFileName, workflowRunsRequest, options).ToObservable();
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableActionsWorkflowsClient.cs b/Octokit.Reactive/Clients/ObservableActionsWorkflowsClient.cs
new file mode 100644
index 0000000000..bd6bb02224
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableActionsWorkflowsClient.cs
@@ -0,0 +1,248 @@
+using System;
+using System.Reactive;
+using System.Reactive.Threading.Tasks;
+
+namespace Octokit.Reactive
+{
+ public class ObservableActionsWorkflowsClient : IObservableActionsWorkflowsClient
+ {
+ readonly IActionsWorkflowsClient _client;
+
+ ///
+ /// Instantiate a new GitHub Actions Workflows API client.
+ ///
+ /// A GitHub client.
+ public ObservableActionsWorkflowsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Actions.Workflows;
+
+ Jobs = new ObservableActionsWorkflowJobsClient(client);
+ Runs = new ObservableActionsWorkflowRunsClient(client);
+ }
+
+ ///
+ /// Manually triggers a GitHub Actions workflow run in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#create-a-workflow-dispatch-event
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ /// The parameters to use to trigger the workflow run.
+ public IObservable CreateDispatch(string owner, string name, string workflowFileName, CreateWorkflowDispatch createDispatch)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+ Ensure.ArgumentNotNull(createDispatch, nameof(createDispatch));
+
+ return _client.CreateDispatch(owner, name, workflowFileName, createDispatch).ToObservable();
+ }
+
+ ///
+ /// Manually triggers a GitHub Actions workflow run in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#create-a-workflow-dispatch-event
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ /// The parameters to use to trigger the workflow run.
+ public IObservable CreateDispatch(string owner, string name, long workflowId, CreateWorkflowDispatch createDispatch)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(createDispatch, nameof(createDispatch));
+
+ return _client.CreateDispatch(owner, name, workflowId, createDispatch).ToObservable();
+ }
+
+ ///
+ /// Disables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#disable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ public IObservable Disable(string owner, string name, string workflowFileName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+
+ return _client.Disable(owner, name, workflowFileName).ToObservable();
+ }
+
+ ///
+ /// Disables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#disable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ public IObservable Disable(string owner, string name, long workflowId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Disable(owner, name, workflowId).ToObservable();
+ }
+
+ ///
+ /// Enables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#enable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ public IObservable Enable(string owner, string name, string workflowFileName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+
+ return _client.Enable(owner, name, workflowFileName).ToObservable();
+ }
+
+ ///
+ /// Enables a specific workflow in a repository by Id.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#enable-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ public IObservable Enable(string owner, string name, long workflowId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Enable(owner, name, workflowId).ToObservable();
+ }
+
+ ///
+ /// Gets a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ public IObservable Get(string owner, string name, string workflowFileName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+
+ return _client.Get(owner, name, workflowFileName).ToObservable();
+ }
+
+ ///
+ /// Gets a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-a-workflow
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ public IObservable Get(string owner, string name, long workflowId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.Get(owner, name, workflowId).ToObservable();
+ }
+
+ ///
+ /// Gets useage of a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-workflow-usage
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The workflow file name.
+ public IObservable GetUsage(string owner, string name, string workflowFileName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNullOrEmptyString(workflowFileName, nameof(workflowFileName));
+
+ return _client.GetUsage(owner, name, workflowFileName).ToObservable();
+ }
+
+ ///
+ /// Gets useage of a specific workflow in a repository by Id. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#get-workflow-usage
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// The Id of the workflow.
+ public IObservable GetUsage(string owner, string name, long workflowId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.GetUsage(owner, name, workflowId).ToObservable();
+ }
+
+ ///
+ /// Lists the workflows in a repository. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#list-repository-workflows
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ public IObservable List(string owner, string name)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+
+ return _client.List(owner, name).ToObservable();
+ }
+
+ ///
+ /// Lists the workflows in a repository. Anyone with read access to the repository can use this endpoint.
+ ///
+ ///
+ /// https://developer.github.com/v3/actions/workflows/#list-repository-workflows
+ ///
+ /// The owner of the repository.
+ /// The name of the repository.
+ /// Options to change the API response.
+ public IObservable List(string owner, string name, ApiOptions options)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(name, nameof(name));
+ Ensure.ArgumentNotNull(options, nameof(options));
+
+ return _client.List(owner, name, options).ToObservable();
+ }
+
+ ///
+ /// Client for the Workflow jobs API.
+ ///
+ public IObservableActionsWorkflowJobsClient Jobs { get; private set; }
+
+ ///
+ /// Client for the Workflow runs API.
+ ///
+ public IObservableActionsWorkflowRunsClient Runs { get; private set; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs
index 833a88514a..072dd79d41 100644
--- a/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs
+++ b/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Octokit.Reactive
+namespace Octokit.Reactive
{
///
/// A client for GitHub's Org Actions API.
diff --git a/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs
index 631bbf4bf4..b49162026e 100644
--- a/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs
+++ b/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Octokit.Reactive
+namespace Octokit.Reactive
{
///
/// A client for GitHub's Repository Actions API.
diff --git a/Octokit.Reactive/IObservableGitHubClient.cs b/Octokit.Reactive/IObservableGitHubClient.cs
index f5ed4393d1..6532de7994 100644
--- a/Octokit.Reactive/IObservableGitHubClient.cs
+++ b/Octokit.Reactive/IObservableGitHubClient.cs
@@ -41,5 +41,6 @@ public interface IObservableGitHubClient : IApiInfoProvider
IObservableLicensesClient Licenses { get; }
IObservableRateLimitClient RateLimit { get; }
IObservableMetaClient Meta { get; }
+ IObservableActionsClient Actions { get; }
}
}
\ No newline at end of file
diff --git a/Octokit.Reactive/ObservableGitHubClient.cs b/Octokit.Reactive/ObservableGitHubClient.cs
index 648360f4c8..c3899ffc77 100644
--- a/Octokit.Reactive/ObservableGitHubClient.cs
+++ b/Octokit.Reactive/ObservableGitHubClient.cs
@@ -56,6 +56,7 @@ public ObservableGitHubClient(IGitHubClient gitHubClient)
Licenses = new ObservableLicensesClient(gitHubClient);
RateLimit = new ObservableRateLimitClient(gitHubClient);
Meta = new ObservableMetaClient(gitHubClient);
+ Actions = new ObservableActionsClient(gitHubClient);
}
public IConnection Connection
@@ -102,6 +103,7 @@ public void SetRequestTimeout(TimeSpan timeout)
public IObservableLicensesClient Licenses { get; private set; }
public IObservableRateLimitClient RateLimit { get; private set; }
public IObservableMetaClient Meta { get; private set; }
+ public IObservableActionsClient Actions { get; private set; }
///
/// Gets the latest API Info - this will be null if no API calls have been made
diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj
index 0ba912abf4..e8de439ecb 100644
--- a/Octokit.Reactive/Octokit.Reactive.csproj
+++ b/Octokit.Reactive/Octokit.Reactive.csproj
@@ -21,7 +21,7 @@
- 1591;1701;1702;1705
+ $(NoWarn);1591;1701;1702;1705
diff --git a/Octokit.Tests.Integration/Clients/ActionsWorkflowJobsClientTests.cs b/Octokit.Tests.Integration/Clients/ActionsWorkflowJobsClientTests.cs
new file mode 100644
index 0000000000..77adf8a478
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/ActionsWorkflowJobsClientTests.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Octokit;
+using Octokit.Tests.Integration;
+using Octokit.Tests.Integration.Helpers;
+using Xunit;
+
+public class ActionsWorkflowJobsClientTests
+{
+ private const string HelloWorldWorkflow = @"
+name: hello
+on: [ push, workflow_dispatch ]
+jobs:
+ world:
+ runs-on: [ ubuntu-latest ]
+ steps:
+ - run: echo ""Hello world.""";
+
+ [IntegrationTest]
+ public async Task CanListWorkflowJobs()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Jobs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForCompletion(github, context);
+
+ var jobs = await fixture.List(owner, name, runId);
+
+ Assert.NotNull(jobs);
+ Assert.NotEqual(0, jobs.TotalCount);
+ Assert.NotNull(jobs.Jobs);
+ Assert.NotEmpty(jobs.Jobs);
+
+ jobs = await fixture.List(owner, name, runId, new WorkflowRunJobsRequest() { Filter = WorkflowRunJobsFilter.All });
+
+ Assert.NotNull(jobs);
+ Assert.NotEqual(0, jobs.TotalCount);
+ Assert.NotNull(jobs.Jobs);
+ Assert.NotEmpty(jobs.Jobs);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowJob()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Jobs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForCompletion(github, context);
+
+ var jobs = await fixture.List(owner, name, runId);
+
+ Assert.NotNull(jobs);
+ Assert.NotNull(jobs.Jobs);
+ Assert.Single(jobs.Jobs);
+
+ var job = await fixture.Get(owner, name, jobs.Jobs[0].Id);
+
+ Assert.NotNull(job);
+ Assert.Equal(jobs.Jobs[0].Id, job.Id);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanListWorkflowJobsForAttempt()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Jobs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForCompletion(github, context);
+
+ var jobs = await fixture.List(owner, name, runId, 1);
+
+ Assert.NotNull(jobs);
+ Assert.NotEqual(0, jobs.TotalCount);
+ Assert.NotNull(jobs.Jobs);
+ Assert.NotEmpty(jobs.Jobs);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowJobLogs()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Jobs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForCompletion(github, context);
+
+ var jobs = await fixture.List(owner, name, runId);
+
+ Assert.NotNull(jobs);
+ Assert.NotNull(jobs.Jobs);
+ var job = Assert.Single(jobs.Jobs);
+
+ var logs = await fixture.GetLogs(owner, name, job.Id);
+
+ Assert.NotNull(logs);
+ Assert.NotEmpty(logs);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanRerunJob()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Jobs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForCompletion(github, context);
+
+ var jobs = await fixture.List(owner, name, runId);
+
+ Assert.NotNull(jobs);
+ Assert.NotNull(jobs.Jobs);
+ var job = Assert.Single(jobs.Jobs);
+
+ await fixture.Rerun(owner, name, job.Id);
+ }
+ }
+
+ private static async Task<(string WorkflowFileName, long RunId)> CreateWorkflowAndWaitForCompletion(
+ IGitHubClient github,
+ RepositoryContext context)
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ var workflowFileName = ".github/workflows/hello-world.yml";
+
+ _ = await github.Repository.Content.CreateFile(
+ owner,
+ name,
+ workflowFileName,
+ new CreateFileRequest("Create test workflow", HelloWorldWorkflow));
+
+ var totalTimeout = TimeSpan.FromMinutes(1);
+ var loopDelay = TimeSpan.FromSeconds(2);
+
+ using (var cts = new CancellationTokenSource(totalTimeout))
+ {
+ while (!cts.IsCancellationRequested)
+ {
+ cts.Token.ThrowIfCancellationRequested();
+
+ var runs = await github.Actions.Workflows.Runs.List(owner, name);
+
+ await Task.Delay(loopDelay);
+
+ if (runs.TotalCount > 0 && runs.WorkflowRuns[0].Status == WorkflowRunStatus.Completed)
+ {
+ return (workflowFileName, runs.WorkflowRuns[0].Id);
+ }
+ }
+ }
+
+ throw new InvalidOperationException("Timed out waiting for workflow run.");
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/ActionsWorkflowRunsClientTests.cs b/Octokit.Tests.Integration/Clients/ActionsWorkflowRunsClientTests.cs
new file mode 100644
index 0000000000..1feab89e4c
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/ActionsWorkflowRunsClientTests.cs
@@ -0,0 +1,407 @@
+using System;
+using System.IO;
+using System.IO.Compression;
+using System.Threading;
+using System.Threading.Tasks;
+using Octokit;
+using Octokit.Tests.Integration;
+using Octokit.Tests.Integration.Helpers;
+using Xunit;
+
+public class ActionsWorkflowRunsClientTests
+{
+ private const string HelloWorldWorkflow = @"
+name: hello
+on: [ push, workflow_dispatch ]
+jobs:
+ world:
+ runs-on: [ ubuntu-latest ]
+ steps:
+ - run: echo ""Hello world.""";
+
+ private const string BrokenWorkflow = @"
+name: hello
+on: [ push, workflow_dispatch ]
+jobs:
+ world:
+ runs-on: [ ubuntu-latest ]
+ steps:
+ - run: exit 1";
+
+ [IntegrationTest]
+ public async Task CanListWorkflowRuns()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, _) = await CreateWorkflowAndWaitForFirstRun(github, context);
+
+ var runs = await fixture.List(owner, name);
+
+ Assert.NotNull(runs);
+ Assert.NotEqual(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.NotEmpty(runs.WorkflowRuns);
+
+ runs = await fixture.List(owner, name, new WorkflowRunsRequest() { Branch = "main" });
+
+ Assert.NotNull(runs);
+ Assert.NotEqual(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.NotEmpty(runs.WorkflowRuns);
+
+ runs = await fixture.List(owner, name, new WorkflowRunsRequest() { Branch = "not-main" });
+
+ Assert.NotNull(runs);
+ Assert.Equal(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.Empty(runs.WorkflowRuns);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowRun()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context);
+
+ var run = await fixture.Get(owner, name, runId);
+
+ Assert.NotNull(run);
+ Assert.Equal(runId, run.Id);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanDeleteWorkflowRun()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context, WorkflowRunStatus.Completed);
+
+ await fixture.Delete(owner, name, runId);
+ await Assert.ThrowsAsync(() => fixture.Get(owner, name, runId));
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanDeleteWorkflowRunLogs()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context, WorkflowRunStatus.Completed);
+
+ await fixture.DeleteLogs(owner, name, runId);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowRunReviewHistory()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context);
+
+ var reviews = await fixture.GetReviewHistory(owner, name, runId);
+ Assert.NotNull(reviews);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowRunAttempt()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context);
+
+ var run = await fixture.GetAttempt(owner, name, runId, 1);
+
+ Assert.NotNull(run);
+ Assert.Equal(runId, run.Id);
+ Assert.Equal(1, run.RunAttempt);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowRunAttemptLogs()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context, WorkflowRunStatus.Completed);
+
+ var logs = await fixture.GetAttemptLogs(owner, name, runId, 1);
+
+ Assert.NotNull(logs);
+ Assert.NotEmpty(logs);
+
+ var tempFile = Path.GetTempFileName();
+
+ try
+ {
+ File.WriteAllBytes(tempFile, logs);
+
+ using (var archive = ZipFile.OpenRead(tempFile))
+ {
+ Assert.NotEmpty(archive.Entries);
+ }
+ }
+ finally
+ {
+ File.Delete(tempFile);
+ }
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowRunLogs()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context, WorkflowRunStatus.Completed);
+
+ var logs = await fixture.GetLogs(owner, name, runId);
+
+ Assert.NotNull(logs);
+ Assert.NotEmpty(logs);
+
+ var tempFile = Path.GetTempFileName();
+
+ try
+ {
+ File.WriteAllBytes(tempFile, logs);
+
+ using (var archive = ZipFile.OpenRead(tempFile))
+ {
+ Assert.NotEmpty(archive.Entries);
+ }
+ }
+ finally
+ {
+ File.Delete(tempFile);
+ }
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanCancelWorkflowRun()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context);
+
+ await fixture.Cancel(owner, name, runId);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanRerunWorkflow()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context, WorkflowRunStatus.Completed);
+
+ await fixture.Rerun(owner, name, runId);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanRerunFailedJobs()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(
+ github,
+ context,
+ WorkflowRunStatus.Completed,
+ BrokenWorkflow);
+
+ await fixture.RerunFailedJobs(owner, name, runId);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowRunUsage()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ (var workflowFileName, var runId) = await CreateWorkflowAndWaitForFirstRun(github, context, WorkflowRunStatus.Completed);
+
+ var usage = await fixture.GetUsage(owner, name, runId);
+
+ Assert.NotNull(usage);
+ Assert.NotEqual(0, usage.RunDurationMs);
+ Assert.NotNull(usage.Billable);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanListWorkflowRunsByWorkflow()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows.Runs;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ (var workflowFileName, _) = await CreateWorkflowAndWaitForFirstRun(github, context);
+
+ var runs = await fixture.ListByWorkflow(owner, name, workflowFileName);
+
+ Assert.NotNull(runs);
+ Assert.NotEqual(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.NotEmpty(runs.WorkflowRuns);
+
+ runs = await fixture.ListByWorkflow(owner, name, workflowFileName, new WorkflowRunsRequest() { Branch = "main" });
+
+ Assert.NotNull(runs);
+ Assert.NotEqual(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.NotEmpty(runs.WorkflowRuns);
+
+ runs = await fixture.ListByWorkflow(owner, name, workflowFileName, new WorkflowRunsRequest() { Branch = "not-main" });
+
+ Assert.NotNull(runs);
+ Assert.Equal(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.Empty(runs.WorkflowRuns);
+
+ var workflowId = await GetWorkflowId(github, context, workflowFileName);
+
+ runs = await fixture.ListByWorkflow(owner, name, workflowId);
+
+ Assert.NotNull(runs);
+ Assert.NotEqual(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.NotEmpty(runs.WorkflowRuns);
+
+ runs = await fixture.ListByWorkflow(owner, name, workflowId, new WorkflowRunsRequest() { Branch = "main" });
+
+ Assert.NotNull(runs);
+ Assert.NotEqual(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.NotEmpty(runs.WorkflowRuns);
+
+ runs = await fixture.ListByWorkflow(owner, name, workflowId, new WorkflowRunsRequest() { Branch = "not-main" });
+
+ Assert.NotNull(runs);
+ Assert.Equal(0, runs.TotalCount);
+ Assert.NotNull(runs.WorkflowRuns);
+ Assert.Empty(runs.WorkflowRuns);
+ }
+ }
+
+ private static async Task<(string WorkflowFileName, long RunId)> CreateWorkflowAndWaitForFirstRun(
+ IGitHubClient github,
+ RepositoryContext context,
+ WorkflowRunStatus? statusToWaitFor = null,
+ string workflowFile = HelloWorldWorkflow)
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ var workflowFileName = ".github/workflows/hello-world.yml";
+
+ _ = await github.Repository.Content.CreateFile(
+ owner,
+ name,
+ workflowFileName,
+ new CreateFileRequest("Create test workflow", workflowFile));
+
+ var totalTimeout = TimeSpan.FromMinutes(1);
+ var loopDelay = TimeSpan.FromSeconds(1);
+
+ using (var cts = new CancellationTokenSource(totalTimeout))
+ {
+ while (!cts.IsCancellationRequested)
+ {
+ cts.Token.ThrowIfCancellationRequested();
+
+ var runs = await github.Actions.Workflows.Runs.List(owner, name);
+
+ await Task.Delay(loopDelay);
+
+ if (runs.TotalCount > 0 && (statusToWaitFor == null || runs.WorkflowRuns[0].Status == statusToWaitFor))
+ {
+ return (workflowFileName, runs.WorkflowRuns[0].Id);
+ }
+ }
+ }
+
+ throw new InvalidOperationException("Timed out waiting for workflow run.");
+ }
+
+ private static async Task GetWorkflowId(
+ IGitHubClient github,
+ RepositoryContext context,
+ string workflowFileName)
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ var workflow = await github.Actions.Workflows.Get(owner, name, workflowFileName);
+ return workflow.Id;
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/ActionsWorkflowsClientTests.cs b/Octokit.Tests.Integration/Clients/ActionsWorkflowsClientTests.cs
new file mode 100644
index 0000000000..59f9e923a5
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/ActionsWorkflowsClientTests.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Threading.Tasks;
+using Octokit;
+using Octokit.Tests.Integration;
+using Octokit.Tests.Integration.Helpers;
+using Xunit;
+
+public class ActionsWorkflowsClientTests
+{
+ private static readonly string HelloWorldWorkflow = @"
+name: hello
+on: [ push, workflow_dispatch ]
+jobs:
+ world:
+ runs-on: [ ubuntu-latest ]
+ steps:
+ - run: echo ""Hello world.""";
+
+ [IntegrationTest]
+ public async Task CanGetWorkflow()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ var workflowFileName = await CreateWorkflow(github, context);
+
+ var workflowByName = await fixture.Get(owner, name, workflowFileName);
+ Assert.NotNull(workflowByName);
+ Assert.Equal(workflowFileName, workflowByName.Path);
+
+ var workflowById = await fixture.Get(owner, name, workflowByName.Id);
+ Assert.NotNull(workflowById);
+ Assert.Equal(workflowByName.Id, workflowById.Id);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanGetWorkflowUsage()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ var workflowFileName = await CreateWorkflow(github, context);
+
+ var usage = await fixture.GetUsage(owner, name, workflowFileName);
+ Assert.NotNull(usage);
+ Assert.NotNull(usage.Billable);
+
+ var workflowId = await GetWorkflowId(github, context, workflowFileName);
+
+ usage = await fixture.GetUsage(owner, name, workflowId);
+ Assert.NotNull(usage);
+ Assert.NotNull(usage.Billable);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanListWorkflows()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ var workflows = await fixture.List(owner, name);
+
+ Assert.NotNull(workflows);
+ Assert.Equal(0, workflows.TotalCount);
+ Assert.NotNull(workflows.Workflows);
+ Assert.Empty(workflows.Workflows);
+
+ var workflowFileName = await CreateWorkflow(github, context);
+
+ workflows = await fixture.List(owner, name);
+
+ Assert.NotNull(workflows);
+ Assert.Equal(1, workflows.TotalCount);
+ Assert.NotNull(workflows.Workflows);
+
+ var workflow = Assert.Single(workflows.Workflows);
+
+ Assert.NotNull(workflow);
+ Assert.Equal(workflowFileName, workflow.Path);
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanDispatchWorkflow()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ var workflowFileName = await CreateWorkflow(github, context);
+ var reference = "main";
+
+ await fixture.CreateDispatch(owner, name, workflowFileName, new CreateWorkflowDispatch(reference));
+
+ var workflowId = await GetWorkflowId(github, context, workflowFileName);
+
+ await fixture.CreateDispatch(owner, name, workflowId, new CreateWorkflowDispatch(reference));
+ }
+ }
+
+ [IntegrationTest]
+ public async Task CanEnableAndDisableWorkflow()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var fixture = github.Actions.Workflows;
+
+ using (var context = await github.CreateRepositoryContextWithAutoInit())
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ var workflowFileName = await CreateWorkflow(github, context);
+ var workflowId = await AssertWorkflowState(github, context, workflowFileName, "active");
+
+ await fixture.Disable(owner, name, workflowId);
+
+ await AssertWorkflowState(github, context, workflowFileName, "disabled_manually");
+
+ await fixture.Enable(owner, name, workflowId);
+
+ await AssertWorkflowState(github, context, workflowFileName, "active");
+
+ await fixture.Disable(owner, name, workflowFileName);
+
+ await AssertWorkflowState(github, context, workflowFileName, "disabled_manually");
+
+ await fixture.Enable(owner, name, workflowFileName);
+
+ await AssertWorkflowState(github, context, workflowFileName, "active");
+ }
+ }
+
+ private static async Task CreateWorkflow(IGitHubClient github, RepositoryContext context)
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+ var workflowFileName = ".github/workflows/hello-world.yml";
+
+ _ = await github.Repository.Content.CreateFile(
+ owner,
+ name,
+ workflowFileName,
+ new CreateFileRequest("Create test workflow", HelloWorldWorkflow));
+
+ await Task.Delay(TimeSpan.FromSeconds(1.5));
+
+ return workflowFileName;
+ }
+
+ private static async Task AssertWorkflowState(
+ IGitHubClient github,
+ RepositoryContext context,
+ string workflowFileName,
+ string expected)
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ var workflow = await github.Actions.Workflows.Get(owner, name, workflowFileName);
+ Assert.NotNull(workflow);
+ Assert.Equal(expected, workflow.State);
+
+ return workflow.Id;
+ }
+
+ private static async Task GetWorkflowId(
+ IGitHubClient github,
+ RepositoryContext context,
+ string workflowFileName)
+ {
+ var owner = context.Repository.Owner.Login;
+ var name = context.Repository.Name;
+
+ var workflow = await github.Actions.Workflows.Get(owner, name, workflowFileName);
+ return workflow.Id;
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/OrganizationActionsClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationActionsClientTests.cs
deleted file mode 100644
index 20548d7b1f..0000000000
--- a/Octokit.Tests.Integration/Clients/OrganizationActionsClientTests.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Octokit.Tests.Integration.Clients
-{
- public class OrganizationActionsClientTests
- {
- }
-}
diff --git a/Octokit.Tests.Integration/Clients/RepositoryActionsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryActionsClientTests.cs
deleted file mode 100644
index 95f60732d1..0000000000
--- a/Octokit.Tests.Integration/Clients/RepositoryActionsClientTests.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Octokit.Tests.Integration.Clients
-{
- public class RepositoryActionsClientTests
- {
- }
-}
diff --git a/Octokit.Tests.Integration/Reactive/ObservableOrganizationActionsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableOrganizationActionsClientTests.cs
deleted file mode 100644
index e05a22c110..0000000000
--- a/Octokit.Tests.Integration/Reactive/ObservableOrganizationActionsClientTests.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Octokit.Tests.Integration.Reactive
-{
- public class ObservableOrganizationActionsClientTests
- {
- }
-}
diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryActionsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryActionsClientTests.cs
deleted file mode 100644
index 3e2ca85d2e..0000000000
--- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryActionsClientTests.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Octokit.Tests.Integration.Reactive
-{
- public class ObservableRepositoryActionsClientTests
- {
- }
-}
diff --git a/Octokit.Tests/Clients/ActionsWorkflowJobsClientTests.cs b/Octokit.Tests/Clients/ActionsWorkflowJobsClientTests.cs
new file mode 100644
index 0000000000..1ec99df17b
--- /dev/null
+++ b/Octokit.Tests/Clients/ActionsWorkflowJobsClientTests.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NSubstitute;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class ActionsWorkflowJobsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new ActionsWorkflowJobsClient(null));
+ }
+ }
+
+ public class TheRerunMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await client.Rerun("fake", "repo", 123);
+
+ connection.Received().Post(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/jobs/123/rerun"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Rerun(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.Rerun("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Rerun("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.Rerun("fake", "", 123));
+ }
+ }
+
+ public class TheGetMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await client.Get("fake", "repo", 123);
+
+ connection.Received().Get(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/jobs/123"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Get(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.Get("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Get("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.Get("fake", "", 123));
+ }
+ }
+
+ public class TheGetLogsMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await client.GetLogs("fake", "repo", 123);
+
+ connection.Connection.Received().Get(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/jobs/123/logs"),
+ null);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetLogs(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetLogs("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetLogs("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetLogs("fake", "", 123));
+ }
+ }
+
+ public class TheListMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await client.List("fake", "repo", 123);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/jobs"),
+ Args.EmptyDictionary,
+ Args.ApiOptions);
+
+ await client.List("fake", "repo", 123, 456);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/attempts/456/jobs"),
+ null,
+ Args.ApiOptions);
+ }
+
+ [Fact]
+ public async Task RequestsCorrectUrlWithRequest()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ var request = new WorkflowRunJobsRequest
+ {
+ Filter = WorkflowRunJobsFilter.All,
+ };
+
+ await client.List("fake", "repo", 123, request);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/jobs"),
+ Arg.Is>(x =>
+ x.Count == 1
+ && x["filter"] == "all"),
+ Args.ApiOptions);
+ }
+
+ [Fact]
+ public async Task RequestsCorrectUrlWithRequestWithApiOptions()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ var request = new WorkflowRunJobsRequest { Filter = WorkflowRunJobsFilter.Latest };
+ var options = new ApiOptions { PageSize = 1 };
+
+ await client.List("fake", "repo", 123, request, options);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/jobs"),
+ Arg.Is>(x =>
+ x.Count == 1
+ && x["filter"] == "latest"),
+ options);
+
+ await client.List("fake", "repo", 123, 456, options);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/attempts/456/jobs"),
+ null,
+ options);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.List(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.List("fake", null, 123));
+
+ await Assert.ThrowsAsync(() => client.List(null, "repo", 123, 456));
+ await Assert.ThrowsAsync(() => client.List("fake", null, 123, 456));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowJobsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.List("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.List("fake", "", 123));
+
+ await Assert.ThrowsAsync(() => client.List("", "repo", 123, 456));
+ await Assert.ThrowsAsync(() => client.List("fake", "", 123, 456));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Clients/ActionsWorkflowRunsClientTests.cs b/Octokit.Tests/Clients/ActionsWorkflowRunsClientTests.cs
new file mode 100644
index 0000000000..21b159e152
--- /dev/null
+++ b/Octokit.Tests/Clients/ActionsWorkflowRunsClientTests.cs
@@ -0,0 +1,839 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Threading.Tasks;
+using NSubstitute;
+using Octokit.Internal;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class ActionsWorkflowRunsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new ActionsWorkflowRunsClient(null));
+ }
+ }
+
+ public class TheApproveMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.Approve("fake", "repo", 123);
+
+ connection.Received().Post(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/approve"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Approve(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.Approve("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Approve("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.Approve("fake", "", 123));
+ }
+ }
+
+ public class TheCancelMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.Cancel("fake", "repo", 123);
+
+ connection.Received().Post(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/cancel"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Cancel(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.Cancel("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Cancel("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.Cancel("fake", "", 123));
+ }
+ }
+
+ public class TheDeleteMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.Delete("fake", "repo", 123);
+
+ connection.Received().Delete(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Delete(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.Delete("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Delete("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.Delete("fake", "", 123));
+ }
+ }
+
+ public class TheDeleteLogsMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.DeleteLogs("fake", "repo", 123);
+
+ connection.Received().Delete(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/logs"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.DeleteLogs(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.DeleteLogs("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.DeleteLogs("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.DeleteLogs("fake", "", 123));
+ }
+ }
+
+ public class TheGetMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.Get("fake", "repo", 123);
+
+ connection.Received().Get(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123"),
+ null);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Get(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.Get("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.Get("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.Get("fake", "", 123));
+ }
+ }
+
+ public class TheGetLogsMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var headers = new Dictionary();
+ var response = TestSetup.CreateResponse(HttpStatusCode.OK, new byte[] { 1, 2, 3, 4 }, headers);
+ var responseTask = Task.FromResult>(new ApiResponse(response));
+
+ var connection = Substitute.For();
+ connection.GetRaw(Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/logs"), null)
+ .Returns(responseTask);
+
+ var apiConnection = Substitute.For();
+ apiConnection.Connection.Returns(connection);
+
+ var client = new ActionsWorkflowRunsClient(apiConnection);
+
+ var actual = await client.GetLogs("fake", "repo", 123);
+
+ Assert.Equal(new byte[] { 1, 2, 3, 4 }, actual);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetLogs(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetLogs("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetLogs("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetLogs("fake", "", 123));
+ }
+ }
+
+ public class TheGetAttemptMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.GetAttempt("fake", "repo", 123, 456);
+
+ connection.Received().Get(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/attempts/456"),
+ null);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetAttempt(null, "repo", 123, 456));
+ await Assert.ThrowsAsync(() => client.GetAttempt("fake", null, 123, 456));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetAttempt("", "repo", 123, 456));
+ await Assert.ThrowsAsync(() => client.GetAttempt("fake", "", 123, 456));
+ }
+ }
+
+ public class TheGetAttemptLogsMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var headers = new Dictionary();
+ var response = TestSetup.CreateResponse(HttpStatusCode.OK, new byte[] { 1, 2, 3, 4 }, headers);
+ var responseTask = Task.FromResult>(new ApiResponse(response));
+
+ var connection = Substitute.For();
+ connection.GetRaw(Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/attempts/456/logs"), null)
+ .Returns(responseTask);
+
+ var apiConnection = Substitute.For();
+ apiConnection.Connection.Returns(connection);
+
+ var client = new ActionsWorkflowRunsClient(apiConnection);
+
+ var actual = await client.GetAttemptLogs("fake", "repo", 123, 456);
+
+ Assert.Equal(new byte[] { 1, 2, 3, 4 }, actual);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetAttemptLogs(null, "repo", 123, 456));
+ await Assert.ThrowsAsync(() => client.GetAttemptLogs("fake", null, 123, 456));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetAttemptLogs("", "repo", 123, 456));
+ await Assert.ThrowsAsync(() => client.GetAttemptLogs("fake", "", 123, 456));
+ }
+ }
+
+ public class TheGetReviewHistoryMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.GetReviewHistory("fake", "repo", 123);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/approvals"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ var workflowRunsRequest = new WorkflowRunsRequest();
+ var options = new ApiOptions();
+
+ await Assert.ThrowsAsync(() => client.GetReviewHistory(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetReviewHistory("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ var workflowRunsRequest = new WorkflowRunsRequest();
+ var options = new ApiOptions();
+
+ await Assert.ThrowsAsync(() => client.GetReviewHistory("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetReviewHistory("fake", "", 123));
+ }
+ }
+
+ public class TheGetUsageMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.GetUsage("fake", "repo", 123);
+
+ connection.Received().Get(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs/123/timing"),
+ null);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetUsage(null, "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetUsage("fake", null, 123));
+ }
+
+ [Fact]
+ public async Task EnsuresNonEmptyArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await Assert.ThrowsAsync(() => client.GetUsage("", "repo", 123));
+ await Assert.ThrowsAsync(() => client.GetUsage("fake", "", 123));
+ }
+ }
+
+ public class TheListMethod
+ {
+ [Fact]
+ public async Task RequestsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ await client.List("fake", "repo");
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs"),
+ Args.EmptyDictionary,
+ Args.ApiOptions);
+ }
+
+ [Fact]
+ public async Task RequestsCorrectUrlWithRequest()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ var request = new WorkflowRunsRequest
+ {
+ Actor = "octocat",
+ Branch = "main",
+ CheckSuiteId = 42,
+ Created = "2020-2022",
+ Event = "push",
+ ExcludePullRequests = true,
+ Status = CheckRunStatusFilter.InProgress,
+ };
+
+ await client.List("fake", "repo", request);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs"),
+ Arg.Is>(x =>
+ x.Count == 7
+ && x["actor"] == "octocat"
+ && x["branch"] == "main"
+ && x["check_suite_id"] == "42"
+ && x["created"] == "2020-2022"
+ && x["event"] == "push"
+ && x["branch"] == "main"
+ && x["exclude_pull_requests"] == "true"
+ && x["status"] == "in_progress"),
+ Args.ApiOptions);
+ }
+
+ [Fact]
+ public async Task RequestsCorrectUrlWithRequestWithApiOptions()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ var request = new WorkflowRunsRequest { Branch = "main", CheckSuiteId = 42, Status = CheckRunStatusFilter.InProgress };
+ var options = new ApiOptions { PageSize = 1 };
+
+ await client.List("fake", "repo", request, options);
+
+ connection.Received().GetAll(
+ Arg.Is(u => u.ToString() == "/repos/fake/repo/actions/runs"),
+ Arg.Is>(x =>
+ x.Count == 3
+ && x["branch"] == "main"
+ && x["status"] == "in_progress"
+ && x["check_suite_id"] == "42"),
+ options);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var connection = Substitute.For();
+ var client = new ActionsWorkflowRunsClient(connection);
+
+ var workflowRunsRequest = new WorkflowRunsRequest();
+ var options = new ApiOptions();
+
+ await Assert.ThrowsAsync(() => client.List(null, "repo"));
+ await Assert.ThrowsAsync(() => client.List("fake", null));
+
+ await Assert.ThrowsAsync(() => client.List(null, "repo", workflowRunsRequest));
+ await Assert.ThrowsAsync