Replay #2221: Implement GitHub Actions Secrets API for both Organization and Repository (#2598)

* created the interface and models for the repository secrets client

* created a repository actions client to sit between repository and secrets for future extensibility

* created the repository secret client and supporting objects to enable data transfer

* created object for create or update secret body and made fixes to pass unit tests

* created repository action unit tests

* created unit tests for RepositorySecretsClient

* removed set from secrets interface

* fixed docs and added observable actions client

* added Actions to repository client

* created IObservable repository secrets client

* fixed property in wrong interface
fixed wrong Ctor unit test

* created repository decrets reactive tests and clients

* created organization actions and scerets classes and made them available through the oprganizations client

* fixed intellisense text

* removed uneeded getall call after return type change

* created organization secret client and classes to support it

* created the observable org secrets client and fixed a typo in a method name

* added more ensure checks

* removed unused xml doc setting

* created the unit tests for the organization secrets client
fixed broken unit test for repository secrets client

* created observable organization actions and secrets client unit tests

* added sodium.core to the integration tests to test secret creation

* fixed keyid type

* added actions client integration test classes (empty since the class currently doesn't have any native methods)

* fixed deserialization issue

* changed property name for deserialization issues

* added doc for repoid on orginzation secrets url generator

* created integration tests for repository and organization secrets

* changed how return occurs for setting list of repos for secret

* fixed some names and removed reset org name

* created integration tests for observable org secrets client

* removed  default org value

* created the integration tests for the observable repository secrets client

* removed default owner project value

* fixed unit tests

* Update links to new docs site

* Update doc links to new docs site

* Update docs links to new docs site

* Fix doc link to point to new docs site

* Update links to new docs site

* Update doc links to new docs site

* Update docs links

* Update docs

* Update docs

* Update doc links

* Update docs

* Update doc links

* Update doc links

* Update doc links

* updated documentation links in actions and secrets clients

* Update Octokit/Models/Response/SecretsPublicKey.cs

Removing line for consistency.

Co-authored-by: Thomas Hughes <iamhughes@github.com>

* Update Octokit/Models/Response/RepositorySecret.cs

Removing line for consistency.

Co-authored-by: Thomas Hughes <iamhughes@github.com>

* set default owner and repo

* switched to using the Helper.Organization from a ORG constant set at the top of the file

* swapped out variable at top of file for the Helper.Organization property

* switched to helper method to create new repositories

* Protected setters --> private setters in response models

* RepositorySecret needs protected setters

Co-authored-by: Mike Tolly <mike.tolly@takeda.com>
Co-authored-by: Thomas Hughes <iamhughes@github.com>
Co-authored-by: mptolly-takeda <61791994+mptolly-takeda@users.noreply.github.com>
This commit is contained in:
Keegan Campbell
2022-10-20 14:59:31 -07:00
committed by GitHub
parent 9c5392b323
commit 131ba87e3f
51 changed files with 3607 additions and 3 deletions

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Org Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions"> Actions API documentation</a> for more information.
/// </remarks>
public interface IObservableOrganizationActionsClient
{
/// <summary>
/// Returns a client to manage organization secrets.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#secrets"> Secrets API documentation</a> for more information.
/// </remarks>
IObservableOrganizationSecretsClient Secrets { get; }
}
}

View File

@@ -0,0 +1,119 @@
using System;
using System.Reactive;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Organization Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#secrets">Organization Secrets API documentation</a> for more details.
/// </remarks>
public interface IObservableOrganizationSecretsClient
{
/// <summary>
/// Get the public signing key to encrypt secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-an-organization-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the organization public key.</returns>
IObservable<SecretsPublicKey> GetPublicKey(string org);
/// <summary>
/// List the secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-organization-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecretsCollection"/> instance for the list of organization secrets.</returns>
IObservable<OrganizationSecretsCollection> GetAll(string org);
/// <summary>
/// Get a secret from an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret.</returns>
IObservable<OrganizationSecret> Get(string org, string secretName);
/// <summary>
/// Create or update a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value, id of the encryption key, and visibility info to upsert</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret that was created or updated.</returns>
IObservable<OrganizationSecret> CreateOrUpdate(string org, string secretName, UpsertOrganizationSecret upsertSecret);
/// <summary>
/// Delete a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#delete-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<Unit> Delete(string org, string secretName);
/// <summary>
/// Get the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<OrganizationSecretRepositoryCollection> GetSelectedRepositoriesForSecret(string org, string secretName);
/// <summary>
/// Set the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#set-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repositories">The list of repositories that should have access to view and use the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<Unit> SetSelectedRepositoriesForSecret(string org, string secretName, SelectedRepositoryCollection repositories);
/// <summary>
/// Add a selected site to the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#add-selected-repository-to-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<Unit> AddRepoToOrganizationSecret(string org, string secretName, long repoId);
/// <summary>
/// ARemoved a selected site from the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#remove-selected-repository-from-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<Unit> RemoveRepoFromOrganizationSecret(string org, string secretName, long repoId);
}
}

View File

@@ -26,6 +26,11 @@ namespace Octokit.Reactive
/// </summary>
IObservableOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; }
/// <summary>
/// Returns a client to manage organization actions.
/// </summary>
IObservableOrganizationActionsClient Actions { get; }
/// <summary>
/// Returns the specified organization.
/// </summary>

View File

@@ -195,6 +195,14 @@ namespace Octokit.Reactive
/// <returns>A <see cref="IReadOnlyPagedCollection{Repository}"/> of <see cref="Repository"/>.</returns>
IObservable<Repository> GetAllForOrg(string organization, ApiOptions options);
/// <summary>
/// Access GitHub's Repository Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">API documentation</a> for more details.
/// </remarks>
IObservableRepositoryActionsClient Actions { get; }
/// <summary>
/// Client for managing branches in a repository.
/// </summary>

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Repository Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Repository Actions API documentation</a> for more details.
/// </remarks>
public interface IObservableRepositoryActionsClient
{
/// <summary>
/// Client for GitHub's Repository Actions API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Deployments API documentation</a> for more details
/// </remarks>
IObservableRepositorySecretsClient Secrets { get; }
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Reactive;
using System.Text;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Repository Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/actions/secrets/">Repository Secrets API documentation</a> for more details.
/// </remarks>
public interface IObservableRepositorySecretsClient
{
/// <summary>
/// Get the public signing key to encrypt secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-a-repository-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the repository public key.</returns>
IObservable<SecretsPublicKey> GetPublicKey(string owner, string repoName);
/// <summary>
/// List the secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-repository-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="IEnumerable{RepositorySecret}"/> instance for the list of repository secrets.</returns>
IObservable<RepositorySecretsCollection> GetAll(string owner, string repoName);
/// <summary>
/// Get a secret from a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret.</returns>
IObservable<RepositorySecret> Get(string owner, string repoName, string secretName);
/// <summary>
/// Create or update a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value and id of the encryption key</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret that was created or updated.</returns>
IObservable<RepositorySecret> CreateOrUpdate(string owner, string repoName, string secretName, UpsertRepositorySecret upsertSecret);
/// <summary>
/// Delete a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#delete-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
IObservable<Unit> Delete(string owner, string repoName, string secretName);
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Org Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions"> Actions API documentation</a> for more information.
/// </remarks>
public class ObservableOrganizationActionsClient : IObservableOrganizationActionsClient
{
readonly IOrganizationActionsClient _client;
readonly IConnection _connection;
/// <summary>
/// Initializes a new Organization API client.
/// </summary>
/// <param name="client">An <see cref="IGitHubClient" /> used to make the requests</param>
public ObservableOrganizationActionsClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, nameof(client));
Secrets = new ObservableOrganizationSecretsClient(client);
_client = client.Organization.Actions;
_connection = client.Connection;
}
/// <summary>
/// Returns a client to manage organization secrets.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#secrets"> Secrets API documentation</a> for more information.
/// </remarks>
public IObservableOrganizationSecretsClient Secrets { get; private set; }
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Reactive;
using System.Reactive.Threading.Tasks;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Organization Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#secrets">Organization Secrets API documentation</a> for more details.
/// </remarks>
public class ObservableOrganizationSecretsClient : IObservableOrganizationSecretsClient
{
readonly IOrganizationSecretsClient _client;
readonly IConnection _connection;
/// <summary>
/// Initializes a new Organization API client.
/// </summary>
/// <param name="client">An <see cref="IGitHubClient" /> used to make the requests</param>
public ObservableOrganizationSecretsClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, nameof(client));
_client = client.Organization.Actions.Secrets;
_connection = client.Connection;
}
/// <summary>
/// Get the public signing key to encrypt secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-an-organization-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the organization public key.</returns>
public IObservable<SecretsPublicKey> GetPublicKey(string org)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
return _client.GetPublicKey(org).ToObservable();
}
/// <summary>
/// List the secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-organization-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecretsCollection"/> instance for the list of organization secrets.</returns>
public IObservable<OrganizationSecretsCollection> GetAll(string org)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
return _client.GetAll(org).ToObservable();
}
/// <summary>
/// Get a secret from an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret.</returns>
public IObservable<OrganizationSecret> Get(string org, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
return _client.Get(org, secretName).ToObservable();
}
/// <summary>
/// Create or update a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value, id of the encryption key, and visibility info to upsert</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret that was created or updated.</returns>
public IObservable<OrganizationSecret> 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();
}
/// <summary>
/// Delete a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#delete-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<Unit> Delete(string org, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
return _client.Delete(org, secretName).ToObservable();
}
/// <summary>
/// Get the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<OrganizationSecretRepositoryCollection> GetSelectedRepositoriesForSecret(string org, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
return _client.GetSelectedRepositoriesForSecret(org, secretName).ToObservable();
}
/// <summary>
/// Set the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#set-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repositories">The list of repositories that should have access to view and use the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<Unit> 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();
}
/// <summary>
/// Add a selected site to the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#add-selected-repository-to-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<Unit> 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();
}
/// <summary>
/// ARemoved a selected site from the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#remove-selected-repository-from-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<Unit> 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();
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using Octokit.Reactive.Internal;
@@ -21,6 +22,7 @@ namespace Octokit.Reactive
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 @@ namespace Octokit.Reactive
/// </summary>
public IObservableOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; private set; }
/// <summary>
/// Returns a client to manage organization actions.
/// </summary>
public IObservableOrganizationActionsClient Actions { get; private set; }
/// <summary>
/// Returns the specified organization.
/// </summary>

View File

@@ -40,6 +40,7 @@ namespace Octokit.Reactive
Invitation = new ObservableRepositoryInvitationsClient(client);
Traffic = new ObservableRepositoryTrafficClient(client);
Project = new ObservableProjectsClient(client);
Actions = new ObservableRepositoryActionsClient(client);
}
/// <summary>
@@ -805,6 +806,14 @@ namespace Octokit.Reactive
return _client.Commit.Compare(owner, name, @base, head).ToObservable();
}
/// <summary>
/// A client for GitHub's Repository Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Actions API documentation</a> for more details
/// </remarks>
public IObservableRepositoryActionsClient Actions { get; private set; }
/// <summary>
/// A client for GitHub's Repository Branches API.
/// </summary>

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Reactive
{
/// <summary>
/// A client for GitHub's Repository Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Repository Actions API documentation</a> for more details.
/// </remarks>
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);
}
/// <summary>
/// Client for GitHub's Repository Actions API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Deployments API documentation</a> for more details
/// </remarks>
public IObservableRepositorySecretsClient Secrets { get; private set; }
}
}

View File

@@ -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
{
/// <summary>
/// A client for GitHub's Repository Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Repository Secrets API documentation</a> for more details.
/// </remarks>
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;
}
/// <summary>
/// Get the public signing key to encrypt secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-a-repository-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the repository public key.</returns>
public IObservable<SecretsPublicKey> GetPublicKey(string owner, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
return _client.GetPublicKey(owner, repoName).ToObservable();
}
/// <summary>
/// List the secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-repository-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="IEnumerable{RepositorySecret}"/> instance for the list of repository secrets.</returns>
public IObservable<RepositorySecretsCollection> GetAll(string owner, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
return _client.GetAll(owner, repoName).ToObservable();
}
/// <summary>
/// Get a secret from a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret.</returns>
public IObservable<RepositorySecret> 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();
}
/// <summary>
/// Create or update a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value and id of the encryption key</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret that was created or updated.</returns>
public IObservable<RepositorySecret> 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();
}
/// <summary>
/// Delete a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#delete-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="repoName">The owner of the repository</param>
/// <param name="owner">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
public IObservable<Unit> 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();
}
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Tests.Integration.Clients
{
public class OrganizationActionsClientTests
{
}
}

View File

@@ -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);
}
}
/// <summary>
/// Please create a secret in your specific repo called TEST
/// </summary>
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<Repository> 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;
}
}
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Tests.Integration.Clients
{
public class RepositoryActionsClientTests
{
}
}

View File

@@ -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
{
/// <summary>
/// Access to view and update secrets is required for the following tests
/// </summary>
public class RespositorySecretsClientTests
{
/// <summary>
/// Fill these in for tests to work
/// </summary>
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);
}
}
/// <summary>
/// Please create a secret in your specific repo called TEST
/// </summary>
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
}
}

View File

@@ -25,7 +25,7 @@
<EmbeddedResource Include="fixtures\hello-world.txt;fixtures\hello-world.zip" Exclude="bin\**;obj\**;**\*.xproj;packages\**;@(EmbeddedResource)" />
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Octokit\Octokit.csproj" />
<ProjectReference Include="..\Octokit.Reactive\Octokit.Reactive.csproj" />

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Tests.Integration.Reactive
{
public class ObservableOrganizationActionsClientTests
{
}
}

View File

@@ -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);
}
}
/// <summary>
/// Please create a secret in your specific repo called TEST
/// </summary>
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
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit.Tests.Integration.Reactive
{
public class ObservableRepositoryActionsClientTests
{
}
}

View File

@@ -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
{
/// <summary>
/// Fill these in for tests to work
/// </summary>
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);
}
}
/// <summary>
/// Please create a secret in your specific repo called TEST
/// </summary>
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
}
}

View File

@@ -0,0 +1,17 @@
using System;
using Xunit;
namespace Octokit.Tests.Clients
{
public class OrganizationActionsClientTests
{
public class TheCtor
{
[Fact]
public void EnsuresNonNullArguments()
{
Assert.Throws<ArgumentNullException>(() => new OrganizationActionsClient(null));
}
}
}
}

View File

@@ -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<ArgumentNullException>(() => new OrganizationSecretsClient(null));
}
}
public class GetPublicKeyMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.GetPublicKey("org");
connection.Received()
.Get<SecretsPublicKey>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/public-key"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetPublicKey(null));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetPublicKey(""));
}
}
public class GetAllMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.GetAll("org");
connection.Received()
.Get<OrganizationSecretsCollection>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll(null));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll(""));
}
}
public class GetMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.Get("org", "secret");
connection.Received()
.Get<OrganizationSecret>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get(null, "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("org", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("org", ""));
}
}
public class CreateOrUpdateMethod
{
[Fact]
public async Task PostsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
var upsertSecret = new UpsertOrganizationSecret
{
EncryptedValue = "encryptedValue",
KeyId = "keyId",
Visibility = "private"
};
await client.CreateOrUpdate("org", "secret", upsertSecret);
connection.Received()
.Put<OrganizationSecret>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret"), upsertSecret);
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
var upsertSecret = new UpsertOrganizationSecret
{
EncryptedValue = "encryptedValue",
KeyId = "keyId"
};
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate(null, "secret", upsertSecret));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", null, upsertSecret));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "secret", null));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "secret", new UpsertOrganizationSecret()));
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("", "secret", upsertSecret));
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("owner", "", upsertSecret));
}
}
public class DeleteMethod
{
[Fact]
public async Task DeletesTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.Delete("org", "secret");
connection.Received()
.Delete(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete(null, "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", ""));
}
}
public class GetSelectedRepositoriesForSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.GetSelectedRepositoriesForSecret("org", "secret");
connection.Received()
.Get<OrganizationSecretRepositoryCollection>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetSelectedRepositoriesForSecret(null, "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetSelectedRepositoriesForSecret("org", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetSelectedRepositoriesForSecret("", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetSelectedRepositoriesForSecret("org", ""));
}
}
public class SetSelectedRepositoriesForSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
var repoIds = new List<long>
{
1,
2,
3
};
var repos = new SelectedRepositoryCollection(repoIds);
await client.SetSelectedRepositoriesForSecret("org", "secret", repos);
connection.Received()
.Put<SelectedRepositoryCollection>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories"), repos);
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
var repoIds = new List<long>
{
1,
2,
3
};
var repos = new SelectedRepositoryCollection(repoIds);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret(null, "secret", repos));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret("org", null, repos));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret("org", "secret", null));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret("org", "secret", new SelectedRepositoryCollection()));
await Assert.ThrowsAsync<ArgumentException>(() => client.SetSelectedRepositoriesForSecret("", "secret", repos));
await Assert.ThrowsAsync<ArgumentException>(() => client.SetSelectedRepositoriesForSecret("org", "", repos));
}
}
public class AddRepoToOrganizationSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.AddRepoToOrganizationSecret("org", "secret", 1);
connection.Received()
.Put(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddRepoToOrganizationSecret(null, "secret", 1));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddRepoToOrganizationSecret("org", null, 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.AddRepoToOrganizationSecret("", "secret", 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.AddRepoToOrganizationSecret("org", "", 1));
}
}
public class RemoveRepoFromOrganizationSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.RemoveRepoFromOrganizationSecret("org", "secret", 1);
connection.Received()
.Delete(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepoFromOrganizationSecret(null, "secret", 1));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepoFromOrganizationSecret("org", null, 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.RemoveRepoFromOrganizationSecret("", "secret", 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.RemoveRepoFromOrganizationSecret("org", "", 1));
}
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using Xunit;
namespace Octokit.Tests.Clients
{
public class RepositoryActionsClientTests
{
public class TheCtor
{
[Fact]
public void EnsuresNonNullArguments()
{
Assert.Throws<ArgumentNullException>(() => new RepositoryActionsClient(null));
}
}
}
}

View File

@@ -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<ArgumentNullException>(() => new RepositorySecretsClient(null));
}
}
public class GetPublicKeyMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new RepositorySecretsClient(connection);
await client.GetPublicKey("owner", "repo");
connection.Received()
.Get<SecretsPublicKey>(Arg.Is<Uri>(u => u.ToString() == "repos/owner/repo/actions/secrets/public-key"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new RepositorySecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetPublicKey(null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetPublicKey("owner", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetPublicKey("", "repo"));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetPublicKey("owner", ""));
}
}
public class GetAllMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new RepositorySecretsClient(connection);
await client.GetAll("owner", "repo");
connection.Received()
.Get<RepositorySecretsCollection>(Arg.Is<Uri>(u => u.ToString() == "repos/owner/repo/actions/secrets"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new RepositorySecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll(null, "repo"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll("owner", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("", "repo"));
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("owner", ""));
}
}
public class GetMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new RepositorySecretsClient(connection);
await client.Get("owner", "repo", "secret");
connection.Received()
.Get<RepositorySecret>(Arg.Is<Uri>(u => u.ToString() == "repos/owner/repo/actions/secrets/secret"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new RepositorySecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get(null, "repo", "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("owner", null, "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("owner", "repo", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("", "repo", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("owner", "", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("owner", "repo", ""));
}
}
public class CreateOrUpdateMethod
{
[Fact]
public async Task PostsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new RepositorySecretsClient(connection);
var upsertSecret = new UpsertRepositorySecret
{
EncryptedValue = "encryptedValue",
KeyId = "keyId"
};
await client.CreateOrUpdate("owner", "repo", "secret", upsertSecret);
connection.Received()
.Put<RepositorySecret>(Arg.Is<Uri>(u => u.ToString() == "repos/owner/repo/actions/secrets/secret"), upsertSecret);
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new RepositorySecretsClient(Substitute.For<IApiConnection>());
var upsertSecret = new UpsertRepositorySecret
{
EncryptedValue = "encryptedValue",
KeyId = "keyId"
};
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate(null, "repo", "secret", upsertSecret));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", null, "secret", upsertSecret));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "repo", null, upsertSecret));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "repo", "secret", null));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "repo", "secret", new UpsertRepositorySecret()));
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("", "repo", "secret", upsertSecret));
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("owner", "", "secret", upsertSecret));
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("owner", "repo", "", upsertSecret));
}
}
public class DeleteMethod
{
[Fact]
public async Task DeletesTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new RepositorySecretsClient(connection);
await client.Delete("owner", "repo", "secret");
connection.Received()
.Delete(Arg.Is<Uri>(u => u.ToString() == "repos/owner/repo/actions/secrets/secret"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new RepositorySecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete(null, "repo", "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", null, "secret"));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", "repo", null));
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("", "repo", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", "", "secret"));
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", "repo", ""));
}
}
}
}

View File

@@ -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<ArgumentNullException>(() => new ObservableOrganizationActionsClient(null));
}
}
}
}

View File

@@ -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<ArgumentNullException>(() => new ObservableOrganizationSecretsClient(null));
}
}
public class GetPublicKeyMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetPublicKey(null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetPublicKey("").ToTask());
}
}
public class GetAllMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll(null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("").ToTask());
}
}
public class GetMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get(null, "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("org", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("org", "").ToTask());
}
}
public class CreateOrUpdateMethod
{
[Fact]
public async Task PostsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
var upsertSecret = new UpsertOrganizationSecret
{
EncryptedValue = "encryptedValue",
KeyId = "keyId"
};
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate(null, "secret", upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", null, upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "secret", null).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "secret", new UpsertOrganizationSecret()).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("", "secret", upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("owner", "", upsertSecret).ToTask());
}
}
public class DeleteMethod
{
[Fact]
public async Task DeletesTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete(null, "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", "").ToTask());
}
}
public class GetSelectedRepositoriesForSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetSelectedRepositoriesForSecret(null, "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetSelectedRepositoriesForSecret("org", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetSelectedRepositoriesForSecret("", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetSelectedRepositoriesForSecret("org", "").ToTask());
}
}
public class SetSelectedRepositoriesForSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
var repoIds = new List<long>
{
1,
2,
3
};
var repos = new SelectedRepositoryCollection(repoIds);
await client.SetSelectedRepositoriesForSecret("org", "secret", repos);
connection.Received()
.Put<SelectedRepositoryCollection>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories"), repos);
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
var repoIds = new List<long>
{
1,
2,
3
};
var repos = new SelectedRepositoryCollection(repoIds);
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret(null, "secret", repos));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret("org", null, repos));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret("org", "secret", null));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SetSelectedRepositoriesForSecret("org", "secret", new SelectedRepositoryCollection()));
await Assert.ThrowsAsync<ArgumentException>(() => client.SetSelectedRepositoriesForSecret("", "secret", repos));
await Assert.ThrowsAsync<ArgumentException>(() => client.SetSelectedRepositoriesForSecret("org", "", repos));
}
}
public class AddRepoToOrganizationSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.AddRepoToOrganizationSecret("org", "secret", 1);
connection.Received()
.Put(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddRepoToOrganizationSecret(null, "secret", 1));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddRepoToOrganizationSecret("org", null, 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.AddRepoToOrganizationSecret("", "secret", 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.AddRepoToOrganizationSecret("org", "", 1));
}
}
public class RemoveRepoFromOrganizationSecretMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var connection = Substitute.For<IApiConnection>();
var client = new OrganizationSecretsClient(connection);
await client.RemoveRepoFromOrganizationSecret("org", "secret", 1);
connection.Received()
.Delete(Arg.Is<Uri>(u => u.ToString() == "orgs/org/actions/secrets/secret/repositories/1"));
}
[Fact]
public async Task EnsuresNonNullArguments()
{
var client = new OrganizationSecretsClient(Substitute.For<IApiConnection>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepoFromOrganizationSecret(null, "secret", 1));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.RemoveRepoFromOrganizationSecret("org", null, 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.RemoveRepoFromOrganizationSecret("", "secret", 1));
await Assert.ThrowsAsync<ArgumentException>(() => client.RemoveRepoFromOrganizationSecret("org", "", 1));
}
}
}
}

View File

@@ -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<ArgumentNullException>(() => new ObservableRepositoryActionsClient(null));
}
}
}
}

View File

@@ -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<ArgumentNullException>(() => new ObservableRepositorySecretsClient(null));
}
}
public class GetPublicKeyMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetPublicKey(null, "repo").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetPublicKey("owner", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetPublicKey("", "repo").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetPublicKey("owner", "").ToTask());
}
}
public class GetAllMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll(null, "repo").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.GetAll("owner", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("", "repo").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.GetAll("owner", "").ToTask());
}
}
public class GetMethod
{
[Fact]
public async Task RequestsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get(null, "repo", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("owner", null, "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Get("owner", "repo", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("", "repo", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("owner", "", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Get("owner", "repo", "").ToTask());
}
}
public class CreateOrUpdateMethod
{
[Fact]
public async Task PostsTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
var upsertSecret = new UpsertRepositorySecret
{
EncryptedValue = "encryptedValue",
KeyId = "keyId"
};
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate(null, "repo", "secret", upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", null, "secret", upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "repo", null, upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "repo", "secret", null).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrUpdate("owner", "repo", "secret", new UpsertRepositorySecret()).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("", "repo", "secret", upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("owner", "", "secret", upsertSecret).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrUpdate("owner", "repo", "", upsertSecret).ToTask());
}
}
public class DeleteMethod
{
[Fact]
public async Task DeletesTheCorrectUrl()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete(null, "repo", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", null, "secret").ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.Delete("owner", "repo", null).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("", "repo", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", "", "secret").ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.Delete("owner", "repo", "").ToTask());
}
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Org Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions"> Actions API documentation</a> for more information.
/// </remarks>
public interface IOrganizationActionsClient
{
/// <summary>
/// Returns a client to manage organization secrets.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#secrets"> Secrets API documentation</a> for more information.
/// </remarks>
IOrganizationSecretsClient Secrets { get; }
}
}

View File

@@ -0,0 +1,118 @@
using System.Threading.Tasks;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Organization Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#secrets">Organization Secrets API documentation</a> for more details.
/// </remarks>
public interface IOrganizationSecretsClient
{
/// <summary>
/// Get the public signing key to encrypt secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-an-organization-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the organization public key.</returns>
Task<SecretsPublicKey> GetPublicKey(string org);
/// <summary>
/// List the secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-organization-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecretsCollection"/> instance for the list of organization secrets.</returns>
Task<OrganizationSecretsCollection> GetAll(string org);
/// <summary>
/// Get a secret from an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#get-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret.</returns>
Task<OrganizationSecret> Get(string org, string secretName);
/// <summary>
/// Create or update a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value, id of the encryption key, and visibility info to upsert</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret that was created or updated.</returns>
Task<OrganizationSecret> CreateOrUpdate(string org, string secretName, UpsertOrganizationSecret upsertSecret);
/// <summary>
/// Delete a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#delete-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task Delete(string org, string secretName);
/// <summary>
/// Get the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#list-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task<OrganizationSecretRepositoryCollection> GetSelectedRepositoriesForSecret(string org, string secretName);
/// <summary>
/// Set the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#set-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repositories">The list of repositories that should have access to view and use the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task SetSelectedRepositoriesForSecret(string org, string secretName, SelectedRepositoryCollection repositories);
/// <summary>
/// Add a selected site to the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#add-selected-repository-to-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task AddRepoToOrganizationSecret(string org, string secretName, long repoId);
/// <summary>
/// ARemoved a selected site from the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions#remove-selected-repository-from-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task RemoveRepoFromOrganizationSecret(string org, string secretName, long repoId);
}
}

View File

@@ -35,6 +35,11 @@ namespace Octokit
/// </summary>
IOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; }
/// <summary>
/// Returns a client to manage organization actions.
/// </summary>
IOrganizationActionsClient Actions { get; }
/// <summary>
/// Returns the specified <see cref="Organization"/>.
/// </summary>

View File

@@ -9,7 +9,7 @@ namespace Octokit
/// A client for GitHub's Repositories API.
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/repos/">Repositories API documentation</a> for more details.
/// See the <https://docs.github.com/en/rest/reference/repos">Repositories API documentation</a> for more details.
/// </remarks>
public interface IRepositoriesClient
{
@@ -17,10 +17,18 @@ namespace Octokit
/// Client for managing pull requests.
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/pulls/">Pull Requests API documentation</a> for more details
/// See the <a href="https://docs.github.com/en/rest/reference/pulls/">Pull Requests API documentation</a> for more details
/// </remarks>
IPullRequestsClient PullRequest { get; }
/// <summary>
/// Client for managing Actions in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Repository Actions API documentation</a> for more information.
/// </remarks>
IRepositoryActionsClient Actions { get; }
/// <summary>
/// Client for managing branches in a repository.
/// </summary>

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Repository Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Repository Actions API documentation</a> for more details.
/// </remarks>
public interface IRepositoryActionsClient
{
/// <summary>
/// Client for GitHub's Repository Actions API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/en/rest/reference/actions">Deployments API documentation</a> for more details
/// </remarks>
IRepositorySecretsClient Secrets { get; }
}
}

View File

@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Repository Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/actions/secrets/">Repository Secrets API documentation</a> for more details.
/// </remarks>
public interface IRepositorySecretsClient
{
/// <summary>
/// Get the public signing key to encrypt secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/secrets/#get-a-repository-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the repository public key.</returns>
Task<SecretsPublicKey> GetPublicKey(string owner, string repoName);
/// <summary>
/// List the secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/secrets/#list-repository-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecretsCollection"/> instance for the list of repository secrets.</returns>
Task<RepositorySecretsCollection> GetAll (string owner, string repoName);
/// <summary>
/// Get a secret from a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/secrets/#get-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret.</returns>
Task<RepositorySecret> Get(string owner, string repoName, string secretName);
/// <summary>
/// Create or update a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/secrets/#create-or-update-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value and id of the encryption key</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret that was created or updated.</returns>
Task<RepositorySecret> CreateOrUpdate(string owner, string repoName, string secretName, UpsertRepositorySecret upsertSecret);
/// <summary>
/// Delete a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://developer.github.com/v3/actions/secrets/#delete-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
Task Delete(string owner, string repoName, string secretName);
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Org Actions API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions/"> Actions API documentation</a> for more information.
/// </remarks>
public class OrganizationActionsClient : ApiClient, IOrganizationActionsClient
{
/// <summary>
/// Initializes a new GitHub Orgs Actions API client.
/// </summary>
/// <param name="apiConnection">An API connection</param>
public OrganizationActionsClient(IApiConnection apiConnection) : base(apiConnection)
{
Secrets = new OrganizationSecretsClient(apiConnection);
}
/// <summary>
/// Returns a client to manage organization secrets.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#secrets"> Secrets API documentation</a> for more information.
/// </remarks>
public IOrganizationSecretsClient Secrets { get; private set; }
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Organization Secrets API.
/// </summary>
/// <remarks>
/// See the <a href="http://docs.github.com/v3/actions#secrets/">Organization Secrets API documentation</a> for more details.
/// </remarks>
public class OrganizationSecretsClient : ApiClient, IOrganizationSecretsClient
{
public OrganizationSecretsClient(IApiConnection apiConnection) : base(apiConnection) { }
/// <summary>
/// Get the public signing key to encrypt secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#get-an-organization-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the organization public key.</returns>
[ManualRoute("GET", "/orgs/{org}/actions/secrets/public-key")]
public Task<SecretsPublicKey> GetPublicKey(string org)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
return ApiConnection.Get<SecretsPublicKey>(ApiUrls.OrganizationRepositorySecretPublicKey(org));
}
/// <summary>
/// List the secrets for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#list-organization-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecretsCollection"/> instance for the list of organization secrets.</returns>
[ManualRoute("GET", "/orgs/{org}/actions/secrets")]
public Task<OrganizationSecretsCollection> GetAll(string org)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
return ApiConnection.Get<OrganizationSecretsCollection>(ApiUrls.OrganizationRepositorySecrets(org));
}
/// <summary>
/// Get a secret from an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#get-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret.</returns>
[ManualRoute("GET", "/orgs/{org}/actions/secrets/{secretName}")]
public Task<OrganizationSecret> Get(string org, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
return ApiConnection.Get<OrganizationSecret>(ApiUrls.OrganizationRepositorySecret(org, secretName));
}
/// <summary>
/// Create or update a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#create-or-update-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value, id of the encryption key, and visibility info to upsert</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="OrganizationSecret"/> instance for the organization secret that was created or updated.</returns>
[ManualRoute("PUT", "/orgs/{org}/actions/secrets/{secretName}")]
public async Task<OrganizationSecret> CreateOrUpdate(string org, string secretName, UpsertOrganizationSecret upsertSecret)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
Ensure.ArgumentNotNull(upsertSecret, nameof(upsertSecret));
Ensure.ArgumentNotNullOrEmptyString(upsertSecret.KeyId, nameof(upsertSecret.KeyId));
Ensure.ArgumentNotNullOrEmptyString(upsertSecret.EncryptedValue, nameof(upsertSecret.EncryptedValue));
Ensure.ArgumentNotNullOrEmptyString(upsertSecret.Visibility, nameof(upsertSecret.Visibility));
await ApiConnection.Put<OrganizationSecret>(ApiUrls.OrganizationRepositorySecret(org, secretName), upsertSecret);
return await ApiConnection.Get<OrganizationSecret>(ApiUrls.OrganizationRepositorySecret(org, secretName));
}
/// <summary>
/// Delete a secret in an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#delete-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("DELETE", "/orgs/{org}/actions/secrets/{secretName}")]
public Task Delete(string org, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
return ApiConnection.Delete(ApiUrls.OrganizationRepositorySecret(org, secretName));
}
/// <summary>
/// Get the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#list-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "/orgs/{org}/actions/secrets/{secretName}/repositories")]
public Task<OrganizationSecretRepositoryCollection> GetSelectedRepositoriesForSecret(string org, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
return ApiConnection.Get<OrganizationSecretRepositoryCollection>(ApiUrls.OrganizationRepositorySecretRepositories(org, secretName));
}
/// <summary>
/// Set the list of selected sites that have access to a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#set-selected-repositories-for-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repositories">The list of repositories that should have access to view and use the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("PUT", "/orgs/{org}/actions/secrets/{secretName}/repositories")]
public async Task SetSelectedRepositoriesForSecret(string org, string secretName, SelectedRepositoryCollection repositories)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
Ensure.ArgumentNotNull(repositories, nameof(repositories));
Ensure.ArgumentNotNull(repositories.SelectedRepositoryIds, nameof(repositories.SelectedRepositoryIds));
await ApiConnection.Put<SelectedRepositoryCollection>(ApiUrls.OrganizationRepositorySecretRepositories(org, secretName), repositories);
return;
}
/// <summary>
/// Add a selected site to the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#add-selected-repository-to-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("PUT", "/orgs/{org}/actions/secrets/{secretName}/repositories/{repoId}")]
public Task AddRepoToOrganizationSecret(string org, string secretName, long repoId)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
Ensure.ArgumentNotNull(repoId, nameof(repoId));
return ApiConnection.Put(ApiUrls.OrganizationRepositorySecretRepository(org, secretName, repoId));
}
/// <summary>
/// ARemoved a selected site from the visibility list of a secret.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#remove-selected-repository-from-an-organization-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="repoId">The id of the repo to add to the visibility list of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("DELETE", "/orgs/{org}/actions/secrets/{secretName}/repositories/{repoId}")]
public Task RemoveRepoFromOrganizationSecret(string org, string secretName, long repoId)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
Ensure.ArgumentNotNull(repoId, nameof(repoId));
return ApiConnection.Delete(ApiUrls.OrganizationRepositorySecretRepository(org, secretName, repoId));
}
}
}

View File

@@ -22,6 +22,7 @@ namespace Octokit
Team = new TeamsClient(apiConnection);
Hook = new OrganizationHooksClient(apiConnection);
OutsideCollaborator = new OrganizationOutsideCollaboratorsClient(apiConnection);
Actions = new OrganizationActionsClient(apiConnection);
}
/// <summary>
@@ -34,6 +35,11 @@ namespace Octokit
/// </summary>
public ITeamsClient Team { get; private set; }
/// <summary>
/// Returns a client to manage organization actions.
/// </summary>
public IOrganizationActionsClient Actions { get; private set; }
/// <summary>
/// Returns a client to manage outside collaborators of an organization.
/// </summary>

View File

@@ -39,6 +39,7 @@ namespace Octokit
Branch = new RepositoryBranchesClient(apiConnection);
Traffic = new RepositoryTrafficClient(apiConnection);
Project = new ProjectsClient(apiConnection);
Actions = new RepositoryActionsClient(apiConnection);
}
/// <summary>
@@ -482,6 +483,14 @@ namespace Octokit
return ApiConnection.GetAll<Repository>(ApiUrls.OrganizationRepositories(organization), null, options);
}
/// <summary>
/// Client for managing Actions in a repository.
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/actions/">Repository Actions API documentation</a> for more information.
/// </remarks>
public IRepositoryActionsClient Actions { get; private set; }
/// <summary>
/// A client for GitHub's Repository Branches API.
/// </summary>

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Repository Actions API.
/// </summary>
/// <remarks>
/// See the <a href="http://docs.github.com/v3/actions">Repository Actions API documentation</a> for more details.
/// </remarks>
public class RepositoryActionsClient : ApiClient, IRepositoryActionsClient
{
/// <summary>
/// Initializes a new GitHub Repository Actions API client.
/// </summary>
/// <param name="apiConnection">An API connection</param>
public RepositoryActionsClient(IApiConnection apiConnection) : base(apiConnection)
{
Secrets = new RepositorySecretsClient(apiConnection);
}
/// <summary>
/// Client for GitHub's Repository Actions API
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#secrets">Deployments API documentation</a> for more details
/// </remarks>
public IRepositorySecretsClient Secrets { get; set; }
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Octokit
{
public class RepositorySecretsClient : ApiClient, IRepositorySecretsClient
{
/// <summary>
/// Initializes a new GitHub Repository Branches API client.
/// </summary>
/// <param name="apiConnection">An API connection</param>
public RepositorySecretsClient(IApiConnection apiConnection) : base(apiConnection)
{
}
/// <summary>
/// Get the public signing key to encrypt secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#get-a-repository-public-key">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="SecretsPublicKey"/> instance for the repository public key.</returns>
[ManualRoute("GET", "/repos/{owner}/{repo}/actions/secrets/public-key")]
public Task<SecretsPublicKey> GetPublicKey(string owner, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
var url = ApiUrls.RepositorySecretsPublicKey(owner, repoName);
return ApiConnection.Get<SecretsPublicKey>(url);
}
/// <summary>
/// List the secrets for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#list-repository-secrets">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecretsCollection"/> instance for the list of repository secrets.</returns>
[ManualRoute("GET", "/repos/{owner}/{repo}/actions/secrets")]
public Task<RepositorySecretsCollection> GetAll(string owner, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
var url = ApiUrls.RepositorySecrets(owner, repoName);
return ApiConnection.Get<RepositorySecretsCollection>(url);
}
/// <summary>
/// Get a secret from a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#get-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret.</returns>
[ManualRoute("GET", "/repos/{owner}/{repo}/actions/secrets/{secretName}")]
public Task<RepositorySecret> Get(string owner, string repoName, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
var url = ApiUrls.RepositorySecret(owner, repoName, secretName);
return ApiConnection.Get<RepositorySecret>(url);
}
/// <summary>
/// Create or update a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#create-or-update-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <param name="upsertSecret">The encrypted value and id of the encryption key</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
/// <returns>A <see cref="RepositorySecret"/> instance for the repository secret that was created or updated.</returns>
[ManualRoute("PUT", "/repos/{owner}/{repo}/actions/secrets/{secretName}")]
public async Task<RepositorySecret> 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));
var url = ApiUrls.RepositorySecret(owner, repoName, secretName);
await ApiConnection.Put<RepositorySecret>(url, upsertSecret);
return await Get(owner, repoName, secretName);
}
/// <summary>
/// Delete a secret in a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/v3/actions#delete-a-repository-secret">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="secretName">The name of the secret</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("DELETE", "/repos/{owner}/{repo}/actions/secrets/{secretName}")]
public Task Delete(string owner, string repoName, string secretName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
Ensure.ArgumentNotNullOrEmptyString(secretName, nameof(secretName));
var url = ApiUrls.RepositorySecret(owner, repoName, secretName);
return ApiConnection.Delete(url);
}
}
}

View File

@@ -78,6 +78,64 @@ namespace Octokit
return "orgs/{0}/repos".FormatUri(organization);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns all of the secrets for the specified organization in
/// response to a GET request.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <returns></returns>
public static Uri OrganizationRepositorySecrets(string organization)
{
return "orgs/{0}/actions/secrets".FormatUri(organization);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns a secret for the specified organization in
/// response to a GET request. A POST to this URL creates a new secret for the organization.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <param name="secret">The name of the secret</param>
/// <returns></returns>
public static Uri OrganizationRepositorySecret(string organization, string secret)
{
return "orgs/{0}/actions/secrets/{1}".FormatUri(organization,secret);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns the public key for signing secrets for the specified organization in
/// response to a GET request.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <returns></returns>
public static Uri OrganizationRepositorySecretPublicKey(string organization)
{
return "orgs/{0}/actions/secrets/public-key".FormatUri(organization);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns a list of repositories for a secret for the specified organization in
/// response to a GET request. A POST to this URL sets the full repository list for a secret in the organization.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <param name="secret">The name of the secret</param>
/// <returns></returns>
public static Uri OrganizationRepositorySecretRepositories(string organization, string secret)
{
return "orgs/{0}/actions/secrets/{1}/repositories".FormatUri(organization, secret);
}
/// <summary>
/// Returns the <see cref="Uri"/> that adds (PUT) or removes (DELETE) a repository from the visibility list of a secret.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <param name="secret">The name of the secret</param>
/// <param name="repoId">The id of the repo to target</param>
/// <returns></returns>
public static Uri OrganizationRepositorySecretRepository(string organization, string secret, long repoId)
{
return "orgs/{0}/actions/secrets/{1}/repositories/{2}".FormatUri(organization, secret, repoId.ToString());
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns all of the organizations for the currently logged in user.
/// </summary>
@@ -4387,6 +4445,40 @@ namespace Octokit
return "repos/{0}/{1}/check-suites/preferences".FormatUri(owner, repo);
}
/// <summary>
/// Returns the <see cref="Uri"/> that handles the repository secrets for the repository
/// </summary>
/// <param name="owner">The owner of the repo</param>
/// <param name="repo">The name of the repo</param>
/// <param name="secret">The name of the secret</param>
/// <returns>The <see cref="Uri"/> that handles the repository secrets for the repository</returns>
public static Uri RepositorySecret(string owner, string repo, string secret)
{
return "repos/{0}/{1}/actions/secrets/{2}".FormatUri(owner, repo, secret);
}
/// <summary>
/// Returns the <see cref="Uri"/> that handles the repository secrets for the repository
/// </summary>
/// <param name="owner">The owner of the repo</param>
/// <param name="repo">The name of the repo</param>
/// <returns>The <see cref="Uri"/> that handles the repository secrets for the repository</returns>
public static Uri RepositorySecrets(string owner, string repo)
{
return "repos/{0}/{1}/actions/secrets".FormatUri(owner, repo);
}
/// <summary>
/// Returns the <see cref="Uri"/> that handles the repository secrets for the repository
/// </summary>
/// <param name="owner">The owner of the repo</param>
/// <param name="repo">The name of the repo</param>
/// <returns>The <see cref="Uri"/> that handles the repository secrets for the repository</returns>
public static Uri RepositorySecretsPublicKey(string owner, string repo)
{
return "repos/{0}/{1}/actions/secrets/public-key".FormatUri(owner, repo);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns all emojis in
/// response to a GET request.

View File

@@ -0,0 +1,32 @@
using Octokit.Internal;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
namespace Octokit
{
/// <summary>
/// Represents request to set the repositories with visibility to the secrets in an organization.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class SelectedRepositoryCollection
{
public SelectedRepositoryCollection()
{
}
public SelectedRepositoryCollection(IEnumerable<long> selectedRepositoryIds)
{
SelectedRepositoryIds = selectedRepositoryIds;
}
/// <summary>
/// List of repository Ids that should have visibility to the repository
/// </summary>
[Parameter(Key = "selected_repository_ids")]
public IEnumerable<long> SelectedRepositoryIds { get; set; }
internal string DebuggerDisplay => string.Format(CultureInfo.CurrentCulture, "SelectedRepositoryCollection: Count: {0}", SelectedRepositoryIds.Count());
}
}

View File

@@ -0,0 +1,38 @@
using Octokit.Internal;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Represents request to change the value of a secret for an organization.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class UpsertOrganizationSecret : UpsertRepositorySecret
{
public UpsertOrganizationSecret() { }
public UpsertOrganizationSecret(string encryptedValue, string encryptionKeyId, string visibility, IEnumerable<long> selectedRepositoriesIds)
{
EncryptedValue = encryptedValue;
KeyId = encryptionKeyId;
Visibility = visibility;
SelectedRepositoriesIds = selectedRepositoriesIds;
}
/// <summary>
/// The visibility level of the secret
/// </summary>
[Parameter(Key = "visibility")]
public string Visibility { get; set; }
/// <summary>
/// The list of ids for the repositories with selected visibility to the secret
/// </summary>
[Parameter(Key = "selected_repository_ids")]
public IEnumerable<long> SelectedRepositoriesIds { get; set; }
internal new string DebuggerDisplay => string.Format(CultureInfo.CurrentCulture, "UpsertOrganizationSecret: Key ID: {0}", KeyId);
}
}

View File

@@ -0,0 +1,35 @@
using Octokit.Internal;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Used to create or update a repository secret
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class UpsertRepositorySecret
{
/// <summary>
/// The encrypted value of the secret.
/// </summary>
/// <remarks>See the <a href="https://developer.github.com/v3/actions/secrets/#create-or-update-a-repository-secret">API documentation</a> for more information on how to encrypt the secret</remarks>
[Parameter(Value = "encrypted_value")]
public string EncryptedValue { get; set; }
/// <summary>
/// The id of the encryption key used to encrypt the secret.
/// </summary>
/// <remarks>Get key and id from <see cref="RepositorySecretsClient.GetPublicKey(string, string)"/> and use the <a href="https://developer.github.com/v3/actions/secrets/#create-or-update-a-repository-secret">API documentation</a> for more information on how to encrypt the secret</remarks>
[Parameter(Value = "key_id")]
public string KeyId { get; set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture, "KeyId: {0}", KeyId);
}
}
}
}

View File

@@ -0,0 +1,39 @@
using Octokit.Internal;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
namespace Octokit
{
/// <summary>
/// Represents an organization secret.
/// Does not contain the secret value
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class OrganizationSecret : RepositorySecret
{
public OrganizationSecret() { }
public OrganizationSecret(string name, DateTime createdAt, DateTime updatedAt, string visibility, string selectedRepositoriesUrl)
{
Name = name;
CreatedAt = createdAt;
UpdatedAt = updatedAt;
Visibility = visibility;
SelectedRepositoriesUrl = selectedRepositoriesUrl;
}
/// <summary>
/// The visibility level of the secret within the organization
/// </summary>
public string Visibility { get; private set; }
/// <summary>
/// The URL to retrieve the list of selected repositories
/// </summary>
[Parameter(Key = "selected_repositories_url")]
public string SelectedRepositoriesUrl { get; private set; }
}
}

View File

@@ -0,0 +1,38 @@
using Octokit.Internal;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Represents response of the repositories for a secret in an organization.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class OrganizationSecretRepositoryCollection
{
public OrganizationSecretRepositoryCollection()
{
}
public OrganizationSecretRepositoryCollection(int count, IReadOnlyList<Repository> repositories)
{
Count = count;
Repositories = repositories;
}
/// <summary>
/// The total count of repositories with visibility to the secret in the organization
/// </summary>
[Parameter(Key = "total_count")]
public int Count { get; private set; }
/// <summary>
/// The list of repositories with visibility to the secret in the organization
/// </summary>
[Parameter(Key = "repositories")]
public IReadOnlyList<Repository> Repositories { get; private set; }
internal string DebuggerDisplay => string.Format(CultureInfo.CurrentCulture, "OrganizationSecretRepositoryCollection: Count: {0}", Count);
}
}

View File

@@ -0,0 +1,38 @@
using Octokit.Internal;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Represents response of secrets for an organization.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class OrganizationSecretsCollection
{
public OrganizationSecretsCollection()
{
}
public OrganizationSecretsCollection(int count, IReadOnlyList<OrganizationSecret> secrets)
{
Count = count;
Secrets = secrets;
}
/// <summary>
/// The total count of secrets for the organization
/// </summary>
[Parameter(Key = "total_count")]
public int Count { get; private set; }
/// <summary>
/// The list of secrets for the organization
/// </summary>
[Parameter(Key = "secrets")]
public IReadOnlyList<OrganizationSecret> Secrets { get; private set; }
internal string DebuggerDisplay => string.Format(CultureInfo.CurrentCulture, "OrganizationSecretCollection: Count: {0}", Count);
}
}

View File

@@ -0,0 +1,50 @@
using Octokit.Internal;
using System;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Represents a repository secret.
/// Does not contain the secret value
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class RepositorySecret
{
public RepositorySecret()
{
}
public RepositorySecret(string name, DateTimeOffset createdAt, DateTimeOffset? updatedAt)
{
Name = name;
CreatedAt = createdAt;
UpdatedAt = updatedAt;
}
/// <summary>
/// The name of the repository secret
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// The date and time that the secret was created
/// </summary>
public DateTimeOffset CreatedAt { get; protected set; }
/// <summary>
/// The date and time the secret was last updated
/// </summary>
public DateTimeOffset? UpdatedAt { get; protected set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"RepositorySecret: Name: {0}", Name);
}
}
}
}

View File

@@ -0,0 +1,36 @@
using Octokit.Internal;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Represents response of secrets for a repository.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class RepositorySecretsCollection
{
public RepositorySecretsCollection()
{
}
public RepositorySecretsCollection(int totalCount, IReadOnlyList<RepositorySecret> secrets)
{
TotalCount = totalCount;
Secrets = secrets;
}
/// <summary>
/// The total count of secrets for the repository
/// </summary>
public int TotalCount { get; private set; }
/// <summary>
/// The list of secrets for the repository
/// </summary>
public IReadOnlyList<RepositorySecret> Secrets { get; private set; }
internal string DebuggerDisplay => string.Format(CultureInfo.CurrentCulture, "RepositorySecretsCollection: Count: {0}", TotalCount);
}
}

View File

@@ -0,0 +1,41 @@
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Represents the public key used to sign the secrets to post to GitHub
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class SecretsPublicKey
{
public SecretsPublicKey()
{
}
public SecretsPublicKey(string keyId, string key)
{
KeyId = keyId;
Key = key;
}
/// <summary>
/// The id of this repository public key. Needed to create or update a secret
/// </summary>
public string KeyId { get; private set; }
/// <summary>
/// The public key for this repository
/// </summary>
public string Key { get; private set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture,
"RepositorySecretPublicKey: Id: {0}", KeyId);
}
}
}
}