Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Environments API Support #240

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions src/GitLabApiClient/EnvironmentClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitLabApiClient.Internal.Http;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Internal.Queries;
using GitLabApiClient.Internal.Utilities;
using GitLabApiClient.Models.Projects.Responses;
using GitLabApiClient.Models.Environments.Requests;
using GitLabApiClient.Models.Environments.Responses;
using Environment = GitLabApiClient.Models.Environments.Responses.Environment;

namespace GitLabApiClient
{
public sealed class EnvironmentClient : IEnvironmentsClient
{
private readonly GitLabHttpFacade _httpFacade;
private readonly EnvironmentsQueryBuilder _environmentQueryBuilder;

internal EnvironmentClient(
GitLabHttpFacade httpFacade,
EnvironmentsQueryBuilder environmentQueryBuilder)
{
_httpFacade = httpFacade;
_environmentQueryBuilder = environmentQueryBuilder;
}

/// <summary>
/// Retrieves an environment by its name
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="environmentId">The ID of the environment to retrieve.</param>
/// <returns></returns>
public async Task<Environment> GetAsync(ProjectId projectId, int environmentId) =>
await _httpFacade.Get<Environment>($"projects/{projectId}/environments/{environmentId}");

/// <summary>
/// Get a list of environments
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="options">Query options <see cref="EnvironmentsQueryOptions"/>.</param>
/// <returns></returns>
public async Task<IList<Environment>> GetAsync(ProjectId projectId, Action<EnvironmentsQueryOptions> options = null)
{
var queryOptions = new EnvironmentsQueryOptions();
options?.Invoke(queryOptions);

string url = _environmentQueryBuilder.Build($"projects/{projectId}/environments", queryOptions);
return await _httpFacade.GetPagedList<Environment>(url);
}

/// <summary>
/// Create an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="request">Create environment request.</param>
/// <returns></returns>
public async Task<Environment> CreateAsync(ProjectId projectId, CreateEnvironmentRequest request) =>
await _httpFacade.Post<Environment>($"projects/{projectId}/environments", request);

/// <summary>
/// Update an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="request">Update environment request</param>
/// <returns></returns>
public async Task<Environment> UpdateAsync(ProjectId projectId, UpdateEnvironmentRequest request) =>
await _httpFacade.Put<Environment>($"projects/{projectId}/environments/{request.EnvironmentId}", request);

/// <summary>
/// Stop an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="tagName">The ID of the environment to stop.</param>
/// <returns></returns>
public async Task StopAsync(ProjectId projectId, int environmentId) =>
await _httpFacade.Post($"projects/{projectId}/environments/{environmentId}/stop");

/// <summary>
/// Delete an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="tagName">The ID of the environment to delete.</param>
/// <returns></returns>
public async Task DeleteAsync(ProjectId projectId, int environmentId) =>
await _httpFacade.Delete($"projects/{projectId}/environments/{environmentId}");
}
}
2 changes: 1 addition & 1 deletion src/GitLabApiClient/GitLabApiClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
</PropertyGroup>

<PropertyGroup Condition=" '$(GITHUB_ACTIONS)' == 'true'">
<ContinuousIntegrationBuild >true</ContinuousIntegrationBuild>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

Expand Down
7 changes: 7 additions & 0 deletions src/GitLabApiClient/GitLabClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
var jobQueryBuilder = new JobQueryBuilder();
var toDoListBuilder = new ToDoListQueryBuilder();
var iterationsBuilder = new IterationsQueryBuilder();
var environmentBuilder = new EnvironmentsQueryBuilder();

Issues = new IssuesClient(_httpFacade, issuesQueryBuilder, projectIssueNotesQueryBuilder);
Uploads = new UploadsClient(_httpFacade);
Expand All @@ -80,6 +81,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
ToDoList = new ToDoListClient(_httpFacade, toDoListBuilder);
Iterations = new IterationsClient(_httpFacade, iterationsBuilder);
Connection = new ConnectionClient(_httpFacade);
Environments = new EnvironmentClient(_httpFacade, environmentBuilder);
}

/// <summary>
Expand Down Expand Up @@ -175,6 +177,11 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
/// <inheritdoc/>
public IIterationsClient Iterations { get; }

/// <summary>
/// Access GitLab's Environments API.
/// </summary>
public IEnvironmentsClient Environments { get; }

/// <summary>
/// Host address of GitLab instance. For example https://gitlab.example.com or https://gitlab.example.com/api/v4/.
/// </summary>
Expand Down
62 changes: 62 additions & 0 deletions src/GitLabApiClient/IEnvironmentsClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Models.Projects.Responses;
using GitLabApiClient.Models.Environments.Requests;
using GitLabApiClient.Models.Environments.Responses;
using Environment = GitLabApiClient.Models.Environments.Responses.Environment;

namespace GitLabApiClient
{
public interface IEnvironmentsClient
{
/// <summary>
/// Get a list of environments
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="environmentId">The ID of the environment to retrieve.</param>
/// <returns></returns>
Task<Environment> GetAsync(ProjectId projectId, int environmentId);

/// <summary>
/// Get a list of environments
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="options">Query options <see cref="EnvironmentsQueryOptions"/>.</param>
/// <returns></returns>
Task<IList<Environment>> GetAsync(ProjectId projectId, Action<EnvironmentsQueryOptions> options = null);

/// <summary>
/// Create an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="request">Create environment request.</param>
/// <returns></returns>
Task<Environment> CreateAsync(ProjectId projectId, CreateEnvironmentRequest request);

/// <summary>
/// Update an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="request">Update environment request</param>
/// <returns></returns>
Task<Environment> UpdateAsync(ProjectId projectId, UpdateEnvironmentRequest request);

/// <summary>
/// Stop an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="environmentId">The ID of the environment to stop.</param>
/// <returns></returns>
Task StopAsync(ProjectId projectId, int environmentId);

/// <summary>
/// Delete an environment
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="environmentId">The ID of the environment to delete.</param>
/// <returns></returns>
Task DeleteAsync(ProjectId projectId, int environmentId);
}
}
23 changes: 23 additions & 0 deletions src/GitLabApiClient/Internal/Queries/EnvironmentsQueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using GitLabApiClient.Models.Environments.Requests;

namespace GitLabApiClient.Internal.Queries
{
class EnvironmentsQueryBuilder : QueryBuilder<EnvironmentsQueryOptions>
{
protected override void BuildCore(Query query, EnvironmentsQueryOptions options)
{
if (!string.IsNullOrEmpty(options.Name) && !string.IsNullOrEmpty(options.Search))
throw new InvalidOperationException("Environment queries for 'name' and 'search' are mutually exclusive.");

if (!string.IsNullOrEmpty(options.Name))
query.Add("name", options.Name);

if (!string.IsNullOrEmpty(options.Search))
query.Add("search", options.Search);

if (options.States != null)
query.Add("states", options.States.ToString().ToLowerInvariant());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using GitLabApiClient.Internal.Utilities;
using GitLabApiClient.Models.Environments.Responses;
using Newtonsoft.Json;
using Environment = GitLabApiClient.Models.Environments.Responses.Environment;

namespace GitLabApiClient.Models.Environments.Requests
{
/// <summary>
/// Used to create an environment in a project.
/// </summary>
public sealed class CreateEnvironmentRequest : Environment
{
/// <summary>
/// Initializes a new instance of the <see cref="CreateEnvironmentRequest"/> class.
/// </summary>
/// <param name="name">The name of the environment.</param>
/// <param name="externalUrl">The external URL for the environment.</param>
public CreateEnvironmentRequest(string name, Uri externalUrl)
{
Guard.NotEmpty(name, nameof(name));
Guard.NotNullOrDefault(externalUrl, nameof(externalUrl));

Name = name;
ExternalUrl = externalUrl;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using GitLabApiClient.Models.Environments.Responses;

namespace GitLabApiClient.Models.Environments.Requests
{
public sealed class EnvironmentsQueryOptions
{
public string Name { get; set; }

public string Search { get; set; }

public EnvironmentState? States { get; set; }

internal EnvironmentsQueryOptions()
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using GitLabApiClient.Internal.Utilities;
using Newtonsoft.Json;

namespace GitLabApiClient.Models.Environments.Requests
{
/// <summary>
/// Used to update an environment in a project
/// </summary>
public sealed class UpdateEnvironmentRequest
{
[JsonProperty("environment_id")]
public int EnvironmentId { get; set; }

[JsonProperty("external_url")]
public Uri ExternalUrl { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="UpdateEnvironmentRequest"/> class
/// </summary>
/// <param name="environmentId">The ID of the environment</param>
/// <param name="externalUrl">The new external URL</param>
public UpdateEnvironmentRequest(int environmentId, Uri externalUrl)
{
Guard.NotNullOrDefault(environmentId, nameof(environmentId));
Guard.NotNullOrDefault(externalUrl, nameof(externalUrl));

EnvironmentId = environmentId;
ExternalUrl = externalUrl;
}
}
}
30 changes: 30 additions & 0 deletions src/GitLabApiClient/Models/Environments/Responses/Environment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using GitLabApiClient.Models.Environments.Responses;
using Newtonsoft.Json;

namespace GitLabApiClient.Models.Environments.Responses
{
public class Environment
{
[JsonProperty("id")]
public int Id { get; set; }

[JsonProperty("name")]
public string Name { get; set; }

[JsonProperty("slug")]
public string Slug { get; set; }

[JsonProperty("external_url")]
public Uri ExternalUrl { get; set; }

[JsonProperty("state")]
public EnvironmentState State { get; set; }

[JsonProperty("created_at")]
public DateTime? CreatedAt { get; set; }

[JsonProperty("updated_at")]
public DateTime? UpdatedAt { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GitLabApiClient.Models.Environments.Responses
{
public enum EnvironmentState
{
Available,
Stopped
}
}
Loading