diff --git a/Octokit.Reactive/Clients/IObservableOrganizationActionsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationActionsClient.cs
new file mode 100644
index 0000000000..f3d00a623c
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableOrganizationActionsClient.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Org Actions API.
+ ///
+ ///
+ /// See the Actions API documentation for more information.
+ ///
+ public interface IObservableOrganizationActionsClient
+ {
+ ///
+ /// Returns a client to manage organization secrets.
+ ///
+ ///
+ /// See the Secrets API documentation for more information.
+ ///
+ IObservableOrganizationSecretsClient Secrets { get; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableOrganizationSecretsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationSecretsClient.cs
new file mode 100644
index 0000000000..205dfeb229
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableOrganizationSecretsClient.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Reactive;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Organization Secrets API.
+ ///
+ ///
+ /// See the Organization Secrets API documentation for more details.
+ ///
+ public interface IObservableOrganizationSecretsClient
+ {
+ ///
+ /// Get the public signing key to encrypt secrets for an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// Thrown when a general API error occurs.
+ /// A instance for the organization public key.
+ IObservable GetPublicKey(string org);
+
+ ///
+ /// List the secrets for an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// Thrown when a general API error occurs.
+ /// A instance for the list of organization secrets.
+ IObservable GetAll(string org);
+
+ ///
+ /// Get a secret from an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ /// A instance for the organization secret.
+ IObservable Get(string org, string secretName);
+
+ ///
+ /// Create or update a secret in an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The encrypted value, id of the encryption key, and visibility info to upsert
+ /// Thrown when a general API error occurs.
+ /// A instance for the organization secret that was created or updated.
+ IObservable CreateOrUpdate(string org, string secretName, UpsertOrganizationSecret upsertSecret);
+
+ ///
+ /// Delete a secret in an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ IObservable Delete(string org, string secretName);
+
+ ///
+ /// Get the list of selected sites that have access to a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ IObservable GetSelectedRepositoriesForSecret(string org, string secretName);
+
+ ///
+ /// Set the list of selected sites that have access to a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The list of repositories that should have access to view and use the secret
+ /// Thrown when a general API error occurs.
+ IObservable SetSelectedRepositoriesForSecret(string org, string secretName, SelectedRepositoryCollection repositories);
+
+ ///
+ /// Add a selected site to the visibility list of a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The id of the repo to add to the visibility list of the secret
+ /// Thrown when a general API error occurs.
+ IObservable AddRepoToOrganizationSecret(string org, string secretName, long repoId);
+
+ ///
+ /// ARemoved a selected site from the visibility list of a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The id of the repo to add to the visibility list of the secret
+ /// Thrown when a general API error occurs.
+ IObservable RemoveRepoFromOrganizationSecret(string org, string secretName, long repoId);
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs
index 8e7596c7c5..d44a187990 100644
--- a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs
+++ b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs
@@ -26,6 +26,11 @@ public interface IObservableOrganizationsClient
///
IObservableOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; }
+ ///
+ /// Returns a client to manage organization actions.
+ ///
+ IObservableOrganizationActionsClient Actions { get; }
+
///
/// Returns the specified organization.
///
diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs
index 562ea50de9..169f86e2ac 100644
--- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs
+++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs
@@ -195,6 +195,14 @@ public interface IObservableRepositoriesClient
/// A of .
IObservable GetAllForOrg(string organization, ApiOptions options);
+ ///
+ /// Access GitHub's Repository Actions API.
+ ///
+ ///
+ /// See the API documentation for more details.
+ ///
+ IObservableRepositoryActionsClient Actions { get; }
+
///
/// Client for managing branches in a repository.
///
diff --git a/Octokit.Reactive/Clients/IObservableRepositoryActionsClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryActionsClient.cs
new file mode 100644
index 0000000000..6f649e0ef4
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableRepositoryActionsClient.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Repository Actions API.
+ ///
+ ///
+ /// See the Repository Actions API documentation for more details.
+ ///
+ public interface IObservableRepositoryActionsClient
+ {
+ ///
+ /// Client for GitHub's Repository Actions API
+ ///
+ ///
+ /// See the Deployments API documentation for more details
+ ///
+ IObservableRepositorySecretsClient Secrets { get; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableRepositorySecretsClient.cs b/Octokit.Reactive/Clients/IObservableRepositorySecretsClient.cs
new file mode 100644
index 0000000000..0d346d0b31
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableRepositorySecretsClient.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Reactive;
+using System.Text;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Repository Secrets API.
+ ///
+ ///
+ /// See the Repository Secrets API documentation for more details.
+ ///
+ public interface IObservableRepositorySecretsClient
+ {
+ ///
+ /// Get the public signing key to encrypt secrets for a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// Thrown when a general API error occurs.
+ /// A instance for the repository public key.
+ IObservable GetPublicKey(string owner, string repoName);
+
+ ///
+ /// List the secrets for a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// Thrown when a general API error occurs.
+ /// A instance for the list of repository secrets.
+ IObservable GetAll(string owner, string repoName);
+
+ ///
+ /// Get a secret from a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ /// A instance for the repository secret.
+ IObservable Get(string owner, string repoName, string secretName);
+
+ ///
+ /// Create or update a secret in a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// The name of the secret
+ /// The encrypted value and id of the encryption key
+ /// Thrown when a general API error occurs.
+ /// A instance for the repository secret that was created or updated.
+ IObservable CreateOrUpdate(string owner, string repoName, string secretName, UpsertRepositorySecret upsertSecret);
+
+ ///
+ /// Delete a secret in a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ IObservable Delete(string owner, string repoName, string secretName);
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs
new file mode 100644
index 0000000000..833a88514a
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableOrganizationActionsClient.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Org Actions API.
+ ///
+ ///
+ /// See the Actions API documentation for more information.
+ ///
+ public class ObservableOrganizationActionsClient : IObservableOrganizationActionsClient
+ {
+ readonly IOrganizationActionsClient _client;
+ readonly IConnection _connection;
+
+ ///
+ /// Initializes a new Organization API client.
+ ///
+ /// An used to make the requests
+ public ObservableOrganizationActionsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ Secrets = new ObservableOrganizationSecretsClient(client);
+
+ _client = client.Organization.Actions;
+ _connection = client.Connection;
+ }
+
+ ///
+ /// Returns a client to manage organization secrets.
+ ///
+ ///
+ /// See the Secrets API documentation for more information.
+ ///
+ public IObservableOrganizationSecretsClient Secrets { get; private set; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableOrganizationSecretsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationSecretsClient.cs
new file mode 100644
index 0000000000..d18febef65
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableOrganizationSecretsClient.cs
@@ -0,0 +1,193 @@
+using System;
+using System.Reactive;
+using System.Reactive.Threading.Tasks;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Organization Secrets API.
+ ///
+ ///
+ /// See the Organization Secrets API documentation for more details.
+ ///
+ public class ObservableOrganizationSecretsClient : IObservableOrganizationSecretsClient
+ {
+ readonly IOrganizationSecretsClient _client;
+ readonly IConnection _connection;
+
+ ///
+ /// Initializes a new Organization API client.
+ ///
+ /// An used to make the requests
+ public ObservableOrganizationSecretsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Organization.Actions.Secrets;
+ _connection = client.Connection;
+ }
+
+ ///
+ /// Get the public signing key to encrypt secrets for an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// Thrown when a general API error occurs.
+ /// A instance for the organization public key.
+ public IObservable GetPublicKey(string org)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+
+ return _client.GetPublicKey(org).ToObservable();
+ }
+
+ ///
+ /// List the secrets for an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// Thrown when a general API error occurs.
+ /// A instance for the list of organization secrets.
+ public IObservable GetAll(string org)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+
+ return _client.GetAll(org).ToObservable();
+ }
+
+ ///
+ /// Get a secret from an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ /// A instance for the organization secret.
+ public IObservable Get(string org, string secretName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+
+ return _client.Get(org, secretName).ToObservable();
+ }
+
+ ///
+ /// Create or update a secret in an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The encrypted value, id of the encryption key, and visibility info to upsert
+ /// Thrown when a general API error occurs.
+ /// A instance for the organization secret that was created or updated.
+ public IObservable CreateOrUpdate(string org, string secretName, UpsertOrganizationSecret upsertSecret)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+ Ensure.ArgumentNotNull(upsertSecret, nameof(upsertSecret));
+ Ensure.ArgumentNotNull(upsertSecret.EncryptedValue, nameof(upsertSecret.EncryptedValue));
+ Ensure.ArgumentNotNull(upsertSecret.KeyId, nameof(upsertSecret.KeyId));
+
+ return _client.CreateOrUpdate(org, secretName, upsertSecret).ToObservable();
+ }
+
+ ///
+ /// Delete a secret in an organization.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ public IObservable Delete(string org, string secretName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+
+ return _client.Delete(org, secretName).ToObservable();
+ }
+
+ ///
+ /// Get the list of selected sites that have access to a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ public IObservable GetSelectedRepositoriesForSecret(string org, string secretName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+
+ return _client.GetSelectedRepositoriesForSecret(org, secretName).ToObservable();
+ }
+
+ ///
+ /// Set the list of selected sites that have access to a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The list of repositories that should have access to view and use the secret
+ /// Thrown when a general API error occurs.
+ public IObservable SetSelectedRepositoriesForSecret(string org, string secretName, SelectedRepositoryCollection repositories)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+ Ensure.ArgumentNotNull(repositories, nameof(repositories));
+
+ return _client.SetSelectedRepositoriesForSecret(org, secretName, repositories).ToObservable();
+ }
+
+ ///
+ /// Add a selected site to the visibility list of a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The id of the repo to add to the visibility list of the secret
+ /// Thrown when a general API error occurs.
+ public IObservable AddRepoToOrganizationSecret(string org, string secretName, long repoId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+ Ensure.ArgumentNotNull(repoId, nameof(repoId));
+
+ return _client.AddRepoToOrganizationSecret(org, secretName, repoId).ToObservable();
+ }
+
+ ///
+ /// ARemoved a selected site from the visibility list of a secret.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The name of the organization
+ /// The name of the secret
+ /// The id of the repo to add to the visibility list of the secret
+ /// Thrown when a general API error occurs.
+ public IObservable RemoveRepoFromOrganizationSecret(string org, string secretName, long repoId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+ Ensure.ArgumentNotNull(repoId, nameof(repoId));
+
+ return _client.RemoveRepoFromOrganizationSecret(org, secretName, repoId).ToObservable();
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs
index 348dc49e83..e90bac920f 100644
--- a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs
+++ b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs
@@ -1,4 +1,5 @@
using System;
+using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using Octokit.Reactive.Internal;
@@ -21,6 +22,7 @@ public ObservableOrganizationsClient(IGitHubClient client)
Team = new ObservableTeamsClient(client);
Hook = new ObservableOrganizationHooksClient(client);
OutsideCollaborator = new ObservableOrganizationOutsideCollaboratorsClient(client);
+ Actions = new ObservableOrganizationActionsClient(client);
_client = client.Organization;
_connection = client.Connection;
@@ -47,6 +49,11 @@ public ObservableOrganizationsClient(IGitHubClient client)
///
public IObservableOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; private set; }
+ ///
+ /// Returns a client to manage organization actions.
+ ///
+ public IObservableOrganizationActionsClient Actions { get; private set; }
+
///
/// Returns the specified organization.
///
diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs
index 13bb249fc2..199fc6fa00 100644
--- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs
+++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs
@@ -40,6 +40,7 @@ public ObservableRepositoriesClient(IGitHubClient client)
Invitation = new ObservableRepositoryInvitationsClient(client);
Traffic = new ObservableRepositoryTrafficClient(client);
Project = new ObservableProjectsClient(client);
+ Actions = new ObservableRepositoryActionsClient(client);
}
///
@@ -805,6 +806,14 @@ public IObservable Compare(string owner, string name, string @bas
return _client.Commit.Compare(owner, name, @base, head).ToObservable();
}
+ ///
+ /// A client for GitHub's Repository Actions API.
+ ///
+ ///
+ /// See the Actions API documentation for more details
+ ///
+ public IObservableRepositoryActionsClient Actions { get; private set; }
+
///
/// A client for GitHub's Repository Branches API.
///
diff --git a/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs
new file mode 100644
index 0000000000..631bbf4bf4
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableRepositoryActionsClient.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Repository Actions API.
+ ///
+ ///
+ /// See the Repository Actions API documentation for more details.
+ ///
+ public class ObservableRepositoryActionsClient : IObservableRepositoryActionsClient
+ {
+ readonly IRepositoryActionsClient _client;
+ readonly IConnection _connection;
+
+ public ObservableRepositoryActionsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Repository.Actions;
+ _connection = client.Connection;
+
+ Secrets = new ObservableRepositorySecretsClient(client);
+ }
+
+ ///
+ /// Client for GitHub's Repository Actions API
+ ///
+ ///
+ /// See the Deployments API documentation for more details
+ ///
+ public IObservableRepositorySecretsClient Secrets { get; private set; }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableRepositorySecretsClient.cs b/Octokit.Reactive/Clients/ObservableRepositorySecretsClient.cs
new file mode 100644
index 0000000000..fa11987edf
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableRepositorySecretsClient.cs
@@ -0,0 +1,128 @@
+using Octokit.Reactive.Internal;
+using System;
+using System.Collections.Generic;
+using System.Reactive;
+using System.Reactive.Threading.Tasks;
+using System.Text;
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's Repository Secrets API.
+ ///
+ ///
+ /// See the Repository Secrets API documentation for more details.
+ ///
+ public class ObservableRepositorySecretsClient : IObservableRepositorySecretsClient
+ {
+ readonly IRepositorySecretsClient _client;
+ readonly IConnection _connection;
+
+ public ObservableRepositorySecretsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, nameof(client));
+
+ _client = client.Repository.Actions.Secrets;
+ _connection = client.Connection;
+ }
+
+ ///
+ /// Get the public signing key to encrypt secrets for a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// Thrown when a general API error occurs.
+ /// A instance for the repository public key.
+ public IObservable GetPublicKey(string owner, string repoName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
+
+ return _client.GetPublicKey(owner, repoName).ToObservable();
+ }
+
+ ///
+ /// List the secrets for a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// Thrown when a general API error occurs.
+ /// A instance for the list of repository secrets.
+ public IObservable GetAll(string owner, string repoName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
+
+ return _client.GetAll(owner, repoName).ToObservable();
+ }
+
+ ///
+ /// Get a secret from a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ /// A instance for the repository secret.
+ public IObservable Get(string owner, string repoName, string secretName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+
+ return _client.Get(owner, repoName, secretName).ToObservable();
+ }
+
+ ///
+ /// Create or update a secret in a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// The name of the secret
+ /// The encrypted value and id of the encryption key
+ /// Thrown when a general API error occurs.
+ /// A instance for the repository secret that was created or updated.
+ public IObservable CreateOrUpdate(string owner, string repoName, string secretName, UpsertRepositorySecret upsertSecret)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+ Ensure.ArgumentNotNull(upsertSecret, nameof(upsertSecret));
+ Ensure.ArgumentNotNullOrEmptyString(upsertSecret.EncryptedValue, nameof(upsertSecret.EncryptedValue));
+ Ensure.ArgumentNotNullOrEmptyString(upsertSecret.KeyId, nameof(upsertSecret.KeyId));
+
+ return _client.CreateOrUpdate(owner, repoName, secretName, upsertSecret).ToObservable();
+ }
+
+ ///
+ /// Delete a secret in a repository.
+ ///
+ ///
+ /// See the API documentation for more information.
+ ///
+ /// The owner of the repository
+ /// The name of the repository
+ /// The name of the secret
+ /// Thrown when a general API error occurs.
+ public IObservable Delete(string owner, string repoName, string secretName)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
+ Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
+ Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
+
+ return _client.Delete(owner, repoName, secretName).ToObservable();
+ }
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/OrganizationActionsClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationActionsClientTests.cs
new file mode 100644
index 0000000000..20548d7b1f
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/OrganizationActionsClientTests.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Tests.Integration.Clients
+{
+ public class OrganizationActionsClientTests
+ {
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/OrganizationSecretsClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationSecretsClientTests.cs
new file mode 100644
index 0000000000..ab93991787
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/OrganizationSecretsClientTests.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using System.Linq;
+
+#if SODIUM_CORE_AVAILABLE
+using Sodium;
+#endif
+
+namespace Octokit.Tests.Integration.Clients
+{
+ public class OrganizationSecretsClientTests
+ {
+
+ public class GetPublicKeyMethod
+ {
+ [OrganizationTest]
+ public async Task GetPublicKey()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var key = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+
+ Assert.True(!string.IsNullOrWhiteSpace(key.KeyId));
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [OrganizationTest]
+ public async Task GetSecrets()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secrets = await github.Organization.Actions.Secrets.GetAll(Helper.Organization);
+
+ Assert.NotEmpty(secrets.Secrets);
+ }
+ }
+
+ ///
+ /// Please create a secret in your specific repo called TEST
+ ///
+ public class GetMethod
+ {
+ [OrganizationTest]
+ public async Task GetSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secret = await github.Organization.Actions.Secrets.Get(Helper.Organization, "TEST");
+
+ Assert.NotNull(secret);
+ Assert.True(secret.Name == "TEST");
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task UpsertSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var now = DateTime.Now;
+
+ var publicKey = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+ var upsertValue = GetSecretForCreate("value", publicKey);
+
+ var secret = await github.Organization.Actions.Secrets.CreateOrUpdate(Helper.Organization, "UPSERT_TEST", upsertValue);
+
+ Assert.NotNull(secret);
+ Assert.True(secret.UpdatedAt > now);
+ }
+#endif
+ }
+
+ public class DeleteMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task DeleteSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secretName = "DELETE_TEST";
+
+ var publicKey = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+ var upsertValue = GetSecretForCreate("value", publicKey);
+
+ await github.Organization.Actions.Secrets.CreateOrUpdate(Helper.Organization, secretName, upsertValue);
+ await github.Organization.Actions.Secrets.Delete(Helper.Organization, secretName);
+
+ }
+#endif
+ }
+
+ public class GetSelectedRepositoriesForSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task GetSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secretName = "LIST_SELECTED_REPO_TEST";
+
+ var repo = await CreateRepoIfNotExists(github, "list-secrets-selected-repo-test");
+
+ var key = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+ var upsertSecret = GetSecretForCreate("secret", key, new Repository[] { repo });
+ var secret = await github.Organization.Actions.Secrets.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+
+ var visibilityRepos = await github.Organization.Actions.Secrets.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ }
+#endif
+ }
+
+ public class SetSelectedRepositoriesForSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task SetSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secretName = "SET_SELECTED_REPO_TEST";
+
+ var repo1 = await CreateRepoIfNotExists(github, "set-secrets-selected-repo-test-1");
+ var repo2 = await CreateRepoIfNotExists(github, "set-secrets-selected-repo-test-2");
+
+ var key = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+ var upsertSecret = GetSecretForCreate("secret", key, new Repository[] { repo1 });
+ await github.Organization.Actions.Secrets.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+
+ await github.Organization.Actions.Secrets.SetSelectedRepositoriesForSecret(Helper.Organization, secretName, new SelectedRepositoryCollection(new long[] { repo1.Id, repo2.Id }));
+
+ var visibilityRepos = await github.Organization.Actions.Secrets.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ Assert.Equal(2, visibilityRepos.Count);
+ }
+#endif
+ }
+
+ public class AddRepoToOrganizationSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task AddSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secretName = "ADD_SELECTED_REPO_TEST";
+
+ var repo1 = await CreateRepoIfNotExists(github, "add-secrets-selected-repo-test-1");
+ var repo2 = await CreateRepoIfNotExists(github, "add-secrets-selected-repo-test-2");
+
+ var key = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+ var upsertSecret = GetSecretForCreate("secret", key, new Repository[] { repo1 });
+ await github.Organization.Actions.Secrets.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+
+ await github.Organization.Actions.Secrets.AddRepoToOrganizationSecret(Helper.Organization, secretName, repo2.Id);
+
+ var visibilityRepos = await github.Organization.Actions.Secrets.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ Assert.Equal(2, visibilityRepos.Count);
+ }
+#endif
+ }
+
+ public class RemoveRepoFromOrganizationSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task RemoveSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secretName = "REMOVE_SELECTED_REPO_TEST";
+
+ var repo1 = await CreateRepoIfNotExists(github, "remove-secrets-selected-repo-test-1");
+ var repo2 = await CreateRepoIfNotExists(github, "remove-secrets-selected-repo-test-2");
+
+ var key = await github.Organization.Actions.Secrets.GetPublicKey(Helper.Organization);
+ var upsertSecret = GetSecretForCreate("secret", key, new Repository[] { repo1, repo2 });
+ await github.Organization.Actions.Secrets.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+
+ await github.Organization.Actions.Secrets.RemoveRepoFromOrganizationSecret(Helper.Organization, secretName, repo2.Id);
+
+ var visibilityRepos = await github.Organization.Actions.Secrets.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ Assert.Equal(1, visibilityRepos.Count);
+ }
+#endif
+ }
+
+#if SODIUM_CORE_AVAILABLE
+ private static UpsertOrganizationSecret GetSecretForCreate(string secretValue, SecretsPublicKey key)
+ {
+ var secretBytes = Encoding.UTF8.GetBytes(secretValue);
+ var publicKey = Convert.FromBase64String(key.Key);
+ var sealedPublicKeyBox = SealedPublicKeyBox.Create(secretBytes, publicKey);
+
+ var upsertValue = new UpsertOrganizationSecret
+ {
+ EncryptedValue = Convert.ToBase64String(sealedPublicKeyBox),
+ KeyId = key.KeyId,
+ Visibility = "all"
+
+ };
+
+ return upsertValue;
+ }
+
+ private static UpsertOrganizationSecret GetSecretForCreate(string secretValue, SecretsPublicKey key, Repository[] repos)
+ {
+ var secretBytes = Encoding.UTF8.GetBytes(secretValue);
+ var publicKey = Convert.FromBase64String(key.Key);
+ var sealedPublicKeyBox = SealedPublicKeyBox.Create(secretBytes, publicKey);
+
+ var upsertValue = new UpsertOrganizationSecret
+ {
+ EncryptedValue = Convert.ToBase64String(sealedPublicKeyBox),
+ KeyId = key.KeyId,
+ Visibility = "selected",
+ SelectedRepositoriesIds = repos.Select(r => r.Id)
+
+ };
+
+ return upsertValue;
+ }
+#endif
+
+ private static async Task CreateRepoIfNotExists(IGitHubClient github, string name)
+ {
+ try
+ {
+ var existingRepo = await github.Repository.Get(Helper.Organization, name);
+ return existingRepo;
+ }
+ catch
+ {
+ var newRepo = await github.Repository.Create(Helper.Organization, new NewRepository(name));
+ return newRepo;
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/RepositoryActionsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryActionsClientTests.cs
new file mode 100644
index 0000000000..95f60732d1
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/RepositoryActionsClientTests.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Tests.Integration.Clients
+{
+ public class RepositoryActionsClientTests
+ {
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/RespositorySecretsClientTests.cs b/Octokit.Tests.Integration/Clients/RespositorySecretsClientTests.cs
new file mode 100644
index 0000000000..e56c2d6cc2
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/RespositorySecretsClientTests.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Versioning;
+using System.Text;
+using System.Threading.Tasks;
+using Octokit;
+using Octokit.Tests.Integration;
+using Octokit.Tests.Integration.Helpers;
+using Xunit;
+
+#if SODIUM_CORE_AVAILABLE
+using Sodium;
+#endif
+
+namespace Octokit.Tests.Integration.Clients
+{
+ ///
+ /// Access to view and update secrets is required for the following tests
+ ///
+ public class RespositorySecretsClientTests
+ {
+ ///
+ /// Fill these in for tests to work
+ ///
+ internal const string OWNER = "octokit";
+ internal const string REPO = "octokit.net";
+
+ public class GetPublicKeyMethod
+ {
+ [IntegrationTest]
+ public async Task GetPublicKey()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var key = await github.Repository.Actions.Secrets.GetPublicKey(OWNER, REPO);
+
+ Assert.True(!string.IsNullOrWhiteSpace(key.KeyId));
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [IntegrationTest]
+ public async Task GetSecrets()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secrets = await github.Repository.Actions.Secrets.GetAll(OWNER, REPO);
+
+ Assert.NotEmpty(secrets.Secrets);
+ }
+ }
+
+ ///
+ /// Please create a secret in your specific repo called TEST
+ ///
+ public class GetMethod
+ {
+ [IntegrationTest]
+ public async Task GetSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secret = await github.Repository.Actions.Secrets.Get(OWNER, REPO, "TEST");
+
+ Assert.NotNull(secret);
+ Assert.True(secret.Name == "TEST");
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [IntegrationTest]
+ public async Task UpsertSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var now = DateTime.Now;
+
+ var publicKey = await github.Repository.Actions.Secrets.GetPublicKey(OWNER, REPO);
+ var upsertValue = GetSecretForCreate("value", publicKey);
+
+ var secret = await github.Repository.Actions.Secrets.CreateOrUpdate(OWNER, REPO, "UPSERT_TEST", upsertValue);
+
+ Assert.NotNull(secret);
+ Assert.True(secret.UpdatedAt > now);
+ }
+#endif
+ }
+
+ public class DeleteMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [IntegrationTest]
+ public async Task DeleteSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+
+ var secretName = "DELETE_TEST";
+
+ var publicKey = await github.Repository.Actions.Secrets.GetPublicKey(OWNER, REPO);
+ var upsertValue = GetSecretForCreate("value", publicKey);
+
+ await github.Repository.Actions.Secrets.CreateOrUpdate(OWNER, REPO, secretName, upsertValue);
+ await github.Repository.Actions.Secrets.Delete(OWNER, REPO, secretName);
+
+ }
+#endif
+ }
+#if SODIUM_CORE_AVAILABLE
+ private static UpsertRepositorySecret GetSecretForCreate(string secretValue, SecretsPublicKey key)
+ {
+ var secretBytes = Encoding.UTF8.GetBytes(secretValue);
+ var publicKey = Convert.FromBase64String(key.Key);
+ var sealedPublicKeyBox = SealedPublicKeyBox.Create(secretBytes, publicKey);
+
+ var upsertValue = new UpsertRepositorySecret
+ {
+ EncryptedValue = Convert.ToBase64String(sealedPublicKeyBox),
+ KeyId = key.KeyId
+
+ };
+
+ return upsertValue;
+ }
+#endif
+ }
+}
diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
index 2f00a3dfe2..2f045e2d84 100644
--- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
+++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
@@ -25,7 +25,7 @@
-
+
diff --git a/Octokit.Tests.Integration/Reactive/ObservableOrganizationActionsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableOrganizationActionsClientTests.cs
new file mode 100644
index 0000000000..e05a22c110
--- /dev/null
+++ b/Octokit.Tests.Integration/Reactive/ObservableOrganizationActionsClientTests.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Tests.Integration.Reactive
+{
+ public class ObservableOrganizationActionsClientTests
+ {
+ }
+}
diff --git a/Octokit.Tests.Integration/Reactive/ObservableOrganizationSecretsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableOrganizationSecretsClientTests.cs
new file mode 100644
index 0000000000..9cdf668ba8
--- /dev/null
+++ b/Octokit.Tests.Integration/Reactive/ObservableOrganizationSecretsClientTests.cs
@@ -0,0 +1,290 @@
+using System;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Octokit.Reactive;
+using Xunit;
+using System.Linq;
+using Octokit.Tests.Integration.Helpers;
+
+#if SODIUM_CORE_AVAILABLE
+using Sodium;
+#endif
+
+namespace Octokit.Tests.Integration.Reactive
+{
+ public class ObservableOrganizationSecretsClientTests
+ {
+ public class GetPublicKeyMethod
+ {
+ [OrganizationTest]
+ public async Task GetPublicKey()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+
+ Assert.True(!string.IsNullOrWhiteSpace(key.KeyId));
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [OrganizationTest]
+ public async Task GetSecrets()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretsObservable = clients.GetAll(Helper.Organization);
+ var secrets = await secretsObservable;
+
+ Assert.NotEmpty(secrets.Secrets);
+ }
+ }
+
+ ///
+ /// Please create a secret in your specific repo called TEST
+ ///
+ public class GetMethod
+ {
+ [OrganizationTest]
+ public async Task GetSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretObservable = clients.Get(Helper.Organization, "TEST");
+ var secret = await secretObservable;
+
+ Assert.NotNull(secret);
+ Assert.True(secret.Name == "TEST");
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task UpsertSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+ var now = DateTime.Now;
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+
+ var upsertValue = GetSecretForCreate("value", key);
+
+ var secretObservable = clients.CreateOrUpdate(Helper.Organization, "REACTIVE_UPSERT_TEST", upsertValue);
+ var secret = await secretObservable;
+
+ Assert.NotNull(secret);
+ Assert.True(secret.UpdatedAt > now);
+ }
+#endif
+ }
+
+ public class DeleteMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task DeleteSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretName = "REACTIVE_DELETE_TEST";
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+ var upsertValue = GetSecretForCreate("value", key);
+
+ var createSecretObservable = clients.CreateOrUpdate(Helper.Organization, secretName, upsertValue);
+ await createSecretObservable;
+
+ var deleteSecretObservable = clients.Delete(Helper.Organization, secretName);
+ await deleteSecretObservable;
+ }
+#endif
+ }
+
+ public class GetSelectedRepositoriesForSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task GetSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretName = "REACTIVE_LIST_SELECTED_REPO_TEST";
+
+ var repoName = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test");
+ var repo = await github.CreateRepositoryContext(new NewRepository(repoName));
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+ var upsertSecret = GetSecretForCreate("value", key, new Repository[] { repo.Repository });
+
+ var secretObservable = clients.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+ await secretObservable;
+
+ var visibilityReposObservable = clients.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+ var visibilityRepos = await visibilityReposObservable;
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ }
+#endif
+ }
+
+ public class SetSelectedRepositoriesForSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task SetSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretName = "REACTIVE_SET_SELECTED_REPO_TEST";
+
+ var repo1Name = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test-1");
+ var repo2Name = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test-2");
+
+ var repo1 = await github.CreateRepositoryContext(new NewRepository(repo1Name));
+ var repo2 = await github.CreateRepositoryContext(new NewRepository(repo2Name));
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+ var upsertSecret = GetSecretForCreate("value", key, new Repository[] { repo1.Repository });
+
+ var secretObservable = clients.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+ await secretObservable;
+
+ var setRepoListObservable = clients.SetSelectedRepositoriesForSecret(Helper.Organization, secretName, new SelectedRepositoryCollection(new long[] { repo1.RepositoryId, repo2.RepositoryId }));
+ await setRepoListObservable;
+
+ var visibilityReposObservable = clients.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+ var visibilityRepos = await visibilityReposObservable;
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ Assert.Equal(2, visibilityRepos.Count);
+ }
+#endif
+ }
+
+ public class AddRepoToOrganizationSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task AddSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretName = "REACTIVE_ADD_SELECTED_REPO_TEST";
+
+ var repo1Name = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test-1");
+ var repo2Name = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test-2");
+
+ var repo1 = await github.CreateRepositoryContext(new NewRepository(repo1Name));
+ var repo2 = await github.CreateRepositoryContext(new NewRepository(repo2Name));
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+ var upsertSecret = GetSecretForCreate("value", key, new Repository[] { repo1.Repository });
+
+ var secretObservable = clients.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+ await secretObservable;
+
+ var addRepoListObservable = clients.AddRepoToOrganizationSecret(Helper.Organization, secretName, repo2.RepositoryId);
+ await addRepoListObservable;
+
+ var visibilityReposObservable = clients.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+ var visibilityRepos = await visibilityReposObservable;
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ Assert.Equal(2, visibilityRepos.Count);
+ }
+#endif
+ }
+
+ public class RemoveRepoFromOrganizationSecretMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [OrganizationTest]
+ public async Task RemoveSelectedRepositoriesForSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var clients = new ObservableOrganizationSecretsClient(github);
+
+ var secretName = "REACTIVE_REMOVE_SELECTED_REPO_TEST";
+
+ var repo1Name = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test-1");
+ var repo2Name = Helper.MakeNameWithTimestamp("reactive-add-secrets-selected-repo-test-2");
+
+ var repo1 = await github.CreateRepositoryContext(new NewRepository(repo1Name));
+ var repo2 = await github.CreateRepositoryContext(new NewRepository(repo2Name));
+
+ var keyObservable = clients.GetPublicKey(Helper.Organization);
+ var key = await keyObservable;
+ var upsertSecret = GetSecretForCreate("secret", key, new Repository[] { repo1.Repository, repo2.Repository });
+
+ var secretObservable = clients.CreateOrUpdate(Helper.Organization, secretName, upsertSecret);
+ await secretObservable;
+
+ var removeRepoListObservable = clients.RemoveRepoFromOrganizationSecret(Helper.Organization, secretName, repo2.RepositoryId);
+ await removeRepoListObservable;
+
+ var visibilityReposObservable = clients.GetSelectedRepositoriesForSecret(Helper.Organization, secretName);
+ var visibilityRepos = await visibilityReposObservable;
+
+ Assert.NotEmpty(visibilityRepos.Repositories);
+ Assert.Equal(1, visibilityRepos.Count);
+ }
+#endif
+ }
+
+#if SODIUM_CORE_AVAILABLE
+ private static UpsertOrganizationSecret GetSecretForCreate(string secretValue, SecretsPublicKey key)
+ {
+ var secretBytes = Encoding.UTF8.GetBytes(secretValue);
+ var publicKey = Convert.FromBase64String(key.Key);
+ var sealedPublicKeyBox = SealedPublicKeyBox.Create(secretBytes, publicKey);
+
+ var upsertValue = new UpsertOrganizationSecret
+ {
+ EncryptedValue = Convert.ToBase64String(sealedPublicKeyBox),
+ KeyId = key.KeyId,
+ Visibility = "all"
+
+ };
+
+ return upsertValue;
+ }
+
+ private static UpsertOrganizationSecret GetSecretForCreate(string secretValue, SecretsPublicKey key, Repository[] repos)
+ {
+ var secretBytes = Encoding.UTF8.GetBytes(secretValue);
+ var publicKey = Convert.FromBase64String(key.Key);
+ var sealedPublicKeyBox = SealedPublicKeyBox.Create(secretBytes, publicKey);
+
+ var upsertValue = new UpsertOrganizationSecret
+ {
+ EncryptedValue = Convert.ToBase64String(sealedPublicKeyBox),
+ KeyId = key.KeyId,
+ Visibility = "selected",
+ SelectedRepositoriesIds = repos.Select(r => r.Id)
+
+ };
+
+ return upsertValue;
+ }
+#endif
+ }
+}
diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryActionsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryActionsClientTests.cs
new file mode 100644
index 0000000000..3e2ca85d2e
--- /dev/null
+++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryActionsClientTests.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Octokit.Tests.Integration.Reactive
+{
+ public class ObservableRepositoryActionsClientTests
+ {
+ }
+}
diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositorySecretsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositorySecretsClientTests.cs
new file mode 100644
index 0000000000..bb29cd6175
--- /dev/null
+++ b/Octokit.Tests.Integration/Reactive/ObservableRepositorySecretsClientTests.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using Octokit.Reactive;
+using System.Reactive.Linq;
+
+#if SODIUM_CORE_AVAILABLE
+using Sodium;
+#endif
+
+namespace Octokit.Tests.Integration.Reactive.Clients
+{
+ public class ObservableRepositorySecretsClientTests
+ {
+ ///
+ /// Fill these in for tests to work
+ ///
+ internal const string OWNER = "";
+ internal const string REPO = "";
+
+ public class GetPublicKeyMethod
+ {
+ [IntegrationTest]
+ public async Task GetPublicKey()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var client = new ObservableRepositorySecretsClient(github);
+
+ var keyObservable = client.GetPublicKey(OWNER, REPO);
+ var key = await keyObservable;
+
+ Assert.True(!string.IsNullOrWhiteSpace(key.KeyId));
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [IntegrationTest]
+ public async Task GetSecrets()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var client = new ObservableRepositorySecretsClient(github);
+
+ var secretsObservable = client.GetAll(OWNER, REPO);
+ var secrets = await secretsObservable;
+
+ Assert.NotEmpty(secrets.Secrets);
+ }
+ }
+
+ ///
+ /// Please create a secret in your specific repo called TEST
+ ///
+ public class GetMethod
+ {
+ [IntegrationTest]
+ public async Task GetSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var client = new ObservableRepositorySecretsClient(github);
+ var secretName = "TEST";
+
+ var secretsObservable = client.Get(OWNER, REPO, secretName);
+ var secret = await secretsObservable;
+
+ Assert.NotNull(secret);
+ Assert.True(secret.Name == secretName);
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [IntegrationTest]
+ public async Task UpsertSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var client = new ObservableRepositorySecretsClient(github);
+ var now = DateTime.Now;
+
+ var keyObservable = client.GetPublicKey(OWNER, REPO);
+ var key = await keyObservable;
+ var upsertValue = GetSecretForCreate("value", key);
+
+ var secretObservable = client.CreateOrUpdate(OWNER, REPO, "REACTIVE_UPSERT_TEST", upsertValue);
+ var secret = await secretObservable;
+
+ Assert.NotNull(secret);
+ Assert.True(secret.UpdatedAt > now);
+ }
+#endif
+ }
+
+ public class DeleteMethod
+ {
+#if SODIUM_CORE_AVAILABLE
+ [IntegrationTest]
+ public async Task DeleteSecret()
+ {
+ var github = Helper.GetAuthenticatedClient();
+ var client = new ObservableRepositorySecretsClient(github);
+
+ var secretName = "DELETE_TEST";
+
+ var keyObservable = client.GetPublicKey(OWNER, REPO);
+ var key = await keyObservable;
+ var upsertValue = GetSecretForCreate("value", key);
+
+ var createObservable = client.CreateOrUpdate(OWNER, REPO, secretName, upsertValue);
+ await createObservable;
+
+ var deleteObservable = client.Delete(OWNER, REPO, secretName);
+ await deleteObservable;
+
+ }
+#endif
+ }
+#if SODIUM_CORE_AVAILABLE
+ private static UpsertRepositorySecret GetSecretForCreate(string secretValue, SecretsPublicKey key)
+ {
+ var secretBytes = Encoding.UTF8.GetBytes(secretValue);
+ var publicKey = Convert.FromBase64String(key.Key);
+ var sealedPublicKeyBox = SealedPublicKeyBox.Create(secretBytes, publicKey);
+
+ var upsertValue = new UpsertRepositorySecret
+ {
+ EncryptedValue = Convert.ToBase64String(sealedPublicKeyBox),
+ KeyId = key.KeyId
+
+ };
+
+ return upsertValue;
+ }
+#endif
+ }
+}
diff --git a/Octokit.Tests/Clients/OrganizationActionsClientTests.cs b/Octokit.Tests/Clients/OrganizationActionsClientTests.cs
new file mode 100644
index 0000000000..8ac1ef66a5
--- /dev/null
+++ b/Octokit.Tests/Clients/OrganizationActionsClientTests.cs
@@ -0,0 +1,17 @@
+using System;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class OrganizationActionsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new OrganizationActionsClient(null));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Octokit.Tests/Clients/OrganizationSecretsClientTests.cs b/Octokit.Tests/Clients/OrganizationSecretsClientTests.cs
new file mode 100644
index 0000000000..da08c24e58
--- /dev/null
+++ b/Octokit.Tests/Clients/OrganizationSecretsClientTests.cs
@@ -0,0 +1,286 @@
+using NSubstitute;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class OrganizationSecretsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new OrganizationSecretsClient(null));
+ }
+ }
+
+ public class GetPublicKeyMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.GetPublicKey("org");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/public-key"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetPublicKey(null));
+ await Assert.ThrowsAsync(() => client.GetPublicKey(""));
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.GetAll("org");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetAll(null));
+ await Assert.ThrowsAsync(() => client.GetAll(""));
+ }
+ }
+
+ public class GetMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.Get("org", "secret");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Get(null, "secret"));
+ await Assert.ThrowsAsync(() => client.Get("org", null));
+
+ await Assert.ThrowsAsync(() => client.Get("", "secret"));
+ await Assert.ThrowsAsync(() => client.Get("org", ""));
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+ [Fact]
+ public async Task PostsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+ var upsertSecret = new UpsertOrganizationSecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId",
+ Visibility = "private"
+ };
+ await client.CreateOrUpdate("org", "secret", upsertSecret);
+
+ connection.Received()
+ .Put(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret"), upsertSecret);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ var upsertSecret = new UpsertOrganizationSecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId"
+ };
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "secret", upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "secret", null));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "secret", new UpsertOrganizationSecret()));
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "secret", upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", upsertSecret));
+ }
+ }
+
+ public class DeleteMethod
+ {
+ [Fact]
+ public async Task DeletesTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.Delete("org", "secret");
+
+ connection.Received()
+ .Delete(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Delete(null, "secret"));
+ await Assert.ThrowsAsync(() => client.Delete("owner", null));
+
+ await Assert.ThrowsAsync(() => client.Delete("", "secret"));
+ await Assert.ThrowsAsync(() => client.Delete("owner", ""));
+ }
+ }
+
+ public class GetSelectedRepositoriesForSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.GetSelectedRepositoriesForSecret("org", "secret");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret(null, "secret"));
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret("org", null));
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret("", "secret"));
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret("org", ""));
+ }
+ }
+
+ public class SetSelectedRepositoriesForSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ var repoIds = new List
+ {
+ 1,
+ 2,
+ 3
+ };
+ var repos = new SelectedRepositoryCollection(repoIds);
+
+ await client.SetSelectedRepositoriesForSecret("org", "secret", repos);
+
+ connection.Received()
+ .Put(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories"), repos);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ var repoIds = new List
+ {
+ 1,
+ 2,
+ 3
+ };
+ var repos = new SelectedRepositoryCollection(repoIds);
+
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret(null, "secret", repos));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", null, repos));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", "secret", null));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", "secret", new SelectedRepositoryCollection()));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("", "secret", repos));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", "", repos));
+ }
+ }
+
+ public class AddRepoToOrganizationSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.AddRepoToOrganizationSecret("org", "secret", 1);
+
+ connection.Received()
+ .Put(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret(null, "secret", 1));
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret("org", null, 1));
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret("", "secret", 1));
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret("org", "", 1));
+ }
+ }
+
+ public class RemoveRepoFromOrganizationSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.RemoveRepoFromOrganizationSecret("org", "secret", 1);
+
+ connection.Received()
+ .Delete(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret(null, "secret", 1));
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret("org", null, 1));
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret("", "secret", 1));
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret("org", "", 1));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Clients/RepositoryActionsClientTests.cs b/Octokit.Tests/Clients/RepositoryActionsClientTests.cs
new file mode 100644
index 0000000000..36f977d45d
--- /dev/null
+++ b/Octokit.Tests/Clients/RepositoryActionsClientTests.cs
@@ -0,0 +1,17 @@
+using System;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class RepositoryActionsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new RepositoryActionsClient(null));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Clients/RepositorySecretsClientTests.cs b/Octokit.Tests/Clients/RepositorySecretsClientTests.cs
new file mode 100644
index 0000000000..4e8accaed9
--- /dev/null
+++ b/Octokit.Tests/Clients/RepositorySecretsClientTests.cs
@@ -0,0 +1,171 @@
+using NSubstitute;
+using System;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class RepositorySecretsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new RepositorySecretsClient(null));
+ }
+ }
+
+ public class GetPublicKeyMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new RepositorySecretsClient(connection);
+
+ await client.GetPublicKey("owner", "repo");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "repos/owner/repo/actions/secrets/public-key"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new RepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetPublicKey(null, "repo"));
+ await Assert.ThrowsAsync(() => client.GetPublicKey("owner", null));
+ await Assert.ThrowsAsync(() => client.GetPublicKey("", "repo"));
+ await Assert.ThrowsAsync(() => client.GetPublicKey("owner", ""));
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new RepositorySecretsClient(connection);
+
+ await client.GetAll("owner", "repo");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "repos/owner/repo/actions/secrets"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new RepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetAll(null, "repo"));
+ await Assert.ThrowsAsync(() => client.GetAll("owner", null));
+
+ await Assert.ThrowsAsync(() => client.GetAll("", "repo"));
+ await Assert.ThrowsAsync(() => client.GetAll("owner", ""));
+ }
+ }
+
+ public class GetMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new RepositorySecretsClient(connection);
+
+ await client.Get("owner", "repo", "secret");
+
+ connection.Received()
+ .Get(Arg.Is(u => u.ToString() == "repos/owner/repo/actions/secrets/secret"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new RepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Get(null, "repo", "secret"));
+ await Assert.ThrowsAsync(() => client.Get("owner", null, "secret"));
+ await Assert.ThrowsAsync(() => client.Get("owner", "repo", null));
+
+ await Assert.ThrowsAsync(() => client.Get("", "repo", "secret"));
+ await Assert.ThrowsAsync(() => client.Get("owner", "", "secret"));
+ await Assert.ThrowsAsync(() => client.Get("owner", "repo", ""));
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+ [Fact]
+ public async Task PostsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new RepositorySecretsClient(connection);
+ var upsertSecret = new UpsertRepositorySecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId"
+ };
+ await client.CreateOrUpdate("owner", "repo", "secret", upsertSecret);
+
+ connection.Received()
+ .Put(Arg.Is(u => u.ToString() == "repos/owner/repo/actions/secrets/secret"), upsertSecret);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new RepositorySecretsClient(Substitute.For());
+
+ var upsertSecret = new UpsertRepositorySecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId"
+ };
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "repo", "secret", upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, "secret", upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", null, upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", "secret", null));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", "secret", new UpsertRepositorySecret()));
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "repo", "secret", upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", "secret", upsertSecret));
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", "", upsertSecret));
+ }
+ }
+
+ public class DeleteMethod
+ {
+ [Fact]
+ public async Task DeletesTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new RepositorySecretsClient(connection);
+
+ await client.Delete("owner", "repo", "secret");
+
+ connection.Received()
+ .Delete(Arg.Is(u => u.ToString() == "repos/owner/repo/actions/secrets/secret"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new RepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Delete(null, "repo", "secret"));
+ await Assert.ThrowsAsync(() => client.Delete("owner", null, "secret"));
+ await Assert.ThrowsAsync(() => client.Delete("owner", "repo", null));
+
+ await Assert.ThrowsAsync(() => client.Delete("", "repo", "secret"));
+ await Assert.ThrowsAsync(() => client.Delete("owner", "", "secret"));
+ await Assert.ThrowsAsync(() => client.Delete("owner", "repo", ""));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Reactive/ObservableOrganizationActionsClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationActionsClientTests.cs
new file mode 100644
index 0000000000..1476c76b4f
--- /dev/null
+++ b/Octokit.Tests/Reactive/ObservableOrganizationActionsClientTests.cs
@@ -0,0 +1,20 @@
+using Octokit.Reactive;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+
+namespace Octokit.Tests.Reactive
+{
+ public class ObservableOrganizationActionsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new ObservableOrganizationActionsClient(null));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Reactive/ObservableOrganizationSecretsClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationSecretsClientTests.cs
new file mode 100644
index 0000000000..7e36b26864
--- /dev/null
+++ b/Octokit.Tests/Reactive/ObservableOrganizationSecretsClientTests.cs
@@ -0,0 +1,282 @@
+using NSubstitute;
+using Octokit.Reactive;
+using System;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Reactive
+{
+ public class ObservableOrganizationSecretsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new ObservableOrganizationSecretsClient(null));
+ }
+ }
+
+ public class GetPublicKeyMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableOrganizationSecretsClient(gitHubClient);
+
+ await client.GetPublicKey("org");
+
+ gitHubClient.Received().Organization.Actions.Secrets.GetPublicKey("org");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableOrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetPublicKey(null).ToTask());
+ await Assert.ThrowsAsync(() => client.GetPublicKey("").ToTask());
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableOrganizationSecretsClient(gitHubClient);
+
+ await client.GetAll("org");
+
+ gitHubClient.Received().Organization.Actions.Secrets.GetAll("org");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableOrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetAll(null).ToTask());
+ await Assert.ThrowsAsync(() => client.GetAll("").ToTask());
+ }
+ }
+
+ public class GetMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableOrganizationSecretsClient(gitHubClient);
+
+ await client.Get("org", "secret");
+
+ gitHubClient.Received().Organization.Actions.Secrets.Get("org", "secret");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableOrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Get(null, "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Get("org", null).ToTask());
+
+ await Assert.ThrowsAsync(() => client.Get("", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Get("org", "").ToTask());
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+ [Fact]
+ public async Task PostsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableOrganizationSecretsClient(gitHubClient);
+ var upsertSecret = new UpsertOrganizationSecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId",
+ Visibility = "private"
+ };
+
+ await client.CreateOrUpdate("org", "secret", upsertSecret);
+
+ gitHubClient.Received().Organization.Actions.Secrets.CreateOrUpdate("org", "secret", upsertSecret);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableOrganizationSecretsClient(Substitute.For());
+
+ var upsertSecret = new UpsertOrganizationSecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId"
+ };
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "secret", upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "secret", null).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "secret", new UpsertOrganizationSecret()).ToTask());
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "secret", upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", upsertSecret).ToTask());
+ }
+ }
+
+ public class DeleteMethod
+ {
+ [Fact]
+ public async Task DeletesTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableOrganizationSecretsClient(gitHubClient);
+
+ await client.Delete("org", "secret");
+
+ gitHubClient.Received().Organization.Actions.Secrets.Delete("org", "secret");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableOrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Delete(null, "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Delete("owner", null).ToTask());
+
+ await Assert.ThrowsAsync(() => client.Delete("", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Delete("owner", "").ToTask());
+ }
+ }
+
+ public class GetSelectedRepositoriesForSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableOrganizationSecretsClient(gitHubClient);
+
+ await client.GetSelectedRepositoriesForSecret("org", "secret");
+
+ gitHubClient.Received().Organization.Actions.Secrets.GetSelectedRepositoriesForSecret("org", "secret");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableOrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret(null, "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret("org", null).ToTask());
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret("", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.GetSelectedRepositoriesForSecret("org", "").ToTask());
+ }
+ }
+
+ public class SetSelectedRepositoriesForSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ var repoIds = new List
+ {
+ 1,
+ 2,
+ 3
+ };
+ var repos = new SelectedRepositoryCollection(repoIds);
+
+ await client.SetSelectedRepositoriesForSecret("org", "secret", repos);
+
+ connection.Received()
+ .Put(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories"), repos);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ var repoIds = new List
+ {
+ 1,
+ 2,
+ 3
+ };
+ var repos = new SelectedRepositoryCollection(repoIds);
+
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret(null, "secret", repos));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", null, repos));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", "secret", null));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", "secret", new SelectedRepositoryCollection()));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("", "secret", repos));
+ await Assert.ThrowsAsync(() => client.SetSelectedRepositoriesForSecret("org", "", repos));
+ }
+ }
+
+ public class AddRepoToOrganizationSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.AddRepoToOrganizationSecret("org", "secret", 1);
+
+ connection.Received()
+ .Put(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret(null, "secret", 1));
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret("org", null, 1));
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret("", "secret", 1));
+ await Assert.ThrowsAsync(() => client.AddRepoToOrganizationSecret("org", "", 1));
+ }
+ }
+
+ public class RemoveRepoFromOrganizationSecretMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new OrganizationSecretsClient(connection);
+
+ await client.RemoveRepoFromOrganizationSecret("org", "secret", 1);
+
+ connection.Received()
+ .Delete(Arg.Is(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new OrganizationSecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret(null, "secret", 1));
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret("org", null, 1));
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret("", "secret", 1));
+ await Assert.ThrowsAsync(() => client.RemoveRepoFromOrganizationSecret("org", "", 1));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Reactive/ObservableRepositoryActionsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryActionsClientTests.cs
new file mode 100644
index 0000000000..22b79b8fbc
--- /dev/null
+++ b/Octokit.Tests/Reactive/ObservableRepositoryActionsClientTests.cs
@@ -0,0 +1,20 @@
+using Octokit.Reactive;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+
+namespace Octokit.Tests.Reactive
+{
+ public class ObservableRepositoryActionsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new ObservableRepositoryActionsClient(null));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Reactive/ObservableRepositorySecretsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositorySecretsClientTests.cs
new file mode 100644
index 0000000000..92a57e1c2b
--- /dev/null
+++ b/Octokit.Tests/Reactive/ObservableRepositorySecretsClientTests.cs
@@ -0,0 +1,170 @@
+using NSubstitute;
+using Octokit.Reactive;
+using System;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Reactive
+{
+ public class ObservableRepositorySecretsClientTests
+ {
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(() => new ObservableRepositorySecretsClient(null));
+ }
+ }
+
+ public class GetPublicKeyMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableRepositorySecretsClient(gitHubClient);
+
+ await client.GetPublicKey("owner", "repo");
+
+ gitHubClient.Received().Repository.Actions.Secrets.GetPublicKey("owner", "repo");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableRepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetPublicKey(null, "repo").ToTask());
+ await Assert.ThrowsAsync(() => client.GetPublicKey("owner", null).ToTask());
+ await Assert.ThrowsAsync(() => client.GetPublicKey("", "repo").ToTask());
+ await Assert.ThrowsAsync(() => client.GetPublicKey("owner", "").ToTask());
+ }
+ }
+
+ public class GetAllMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableRepositorySecretsClient(gitHubClient);
+
+ await client.GetAll("owner", "repo");
+
+ gitHubClient.Received().Repository.Actions.Secrets.GetAll("owner", "repo");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableRepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.GetAll(null, "repo").ToTask());
+ await Assert.ThrowsAsync(() => client.GetAll("owner", null).ToTask());
+
+ await Assert.ThrowsAsync(() => client.GetAll("", "repo").ToTask());
+ await Assert.ThrowsAsync(() => client.GetAll("owner", "").ToTask());
+ }
+ }
+
+ public class GetMethod
+ {
+ [Fact]
+ public async Task RequestsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableRepositorySecretsClient(gitHubClient);
+
+ await client.Get("owner", "repo","secret");
+
+ gitHubClient.Received().Repository.Actions.Secrets.Get("owner", "repo", "secret");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableRepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Get(null, "repo", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Get("owner", null, "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Get("owner", "repo", null).ToTask());
+
+ await Assert.ThrowsAsync(() => client.Get("", "repo", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Get("owner", "", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Get("owner", "repo", "").ToTask());
+ }
+ }
+
+ public class CreateOrUpdateMethod
+ {
+ [Fact]
+ public async Task PostsTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableRepositorySecretsClient(gitHubClient);
+ var upsert = new UpsertRepositorySecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId"
+ };
+
+ await client.CreateOrUpdate("owner", "repo", "secret", upsert);
+
+ gitHubClient.Received().Repository.Actions.Secrets.CreateOrUpdate("owner", "repo", "secret", upsert);
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableRepositorySecretsClient(Substitute.For());
+
+ var upsertSecret = new UpsertRepositorySecret
+ {
+ EncryptedValue = "encryptedValue",
+ KeyId = "keyId"
+ };
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "repo", "secret", upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, "secret", upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", null, upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", "secret", null).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", "secret", new UpsertRepositorySecret()).ToTask());
+
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "repo", "secret", upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", "secret", upsertSecret).ToTask());
+ await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "repo", "", upsertSecret).ToTask());
+ }
+ }
+
+ public class DeleteMethod
+ {
+ [Fact]
+ public async Task DeletesTheCorrectUrl()
+ {
+ var gitHubClient = Substitute.For();
+ var client = new ObservableRepositorySecretsClient(gitHubClient);
+
+ await client.Delete("owner", "repo", "secret");
+
+ gitHubClient.Received().Repository.Actions.Secrets.Delete("owner", "repo", "secret");
+ }
+
+ [Fact]
+ public async Task EnsuresNonNullArguments()
+ {
+ var client = new ObservableRepositorySecretsClient(Substitute.For());
+
+ await Assert.ThrowsAsync(() => client.Delete(null, "repo", "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Delete("owner", null, "secret").ToTask());
+ await Assert.ThrowsAsync(() => client.Delete("owner", "repo", null).ToTask());
+
+ await Assert.ThrowsAsync