Skip to content
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
121 changes: 121 additions & 0 deletions src/GitLabApiClient/EpicsClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using GitLabApiClient.Internal.Http;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Internal.Queries;
using GitLabApiClient.Internal.Utilities;
using GitLabApiClient.Models.Epics.Requests;
using GitLabApiClient.Models.Epics.Responses;
using GitLabApiClient.Models.Groups.Requests;
using GitLabApiClient.Models.Issues.Requests;
using GitLabApiClient.Models.Issues.Responses;
using GitLabApiClient.Models.Notes.Requests;
using GitLabApiClient.Models.Notes.Responses;

namespace GitLabApiClient
{
public sealed class EpicsClient : IEpicsClient
{
private readonly GitLabHttpFacade _httpFacade;
private readonly EpicsGroupQueryBuilder _queryBuilder;
private readonly NotesQueryBuilder _notesQueryBuilder;
private readonly IssuesQueryBuilder _issuesQueryBuilder;

internal EpicsClient(GitLabHttpFacade httpFacade, EpicsGroupQueryBuilder queryBuilder, NotesQueryBuilder notesQueryBuilder, IssuesQueryBuilder issuesQueryBuilder)
{
_httpFacade = httpFacade;
_queryBuilder = queryBuilder;
_notesQueryBuilder = notesQueryBuilder;
_issuesQueryBuilder = issuesQueryBuilder;
}

public async Task<Epic> CreateAsync(GroupId groupId, CreateEpicRequest request)
{
Guard.NotNull(request, nameof(request));
return await _httpFacade.Post<Epic>($"groups/{groupId}/epics", request);
}

/// <summary>
/// Retrieves epic by its id from a group.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">The ID of the epic.</param>
/// <returns></returns>
public async Task<Epic> GetAsync(GroupId groupId, int epicId) =>
await _httpFacade.Get<Epic>($"groups/{groupId}/epics/{epicId}");

/// <summary>
/// Retrieves notes (comments) of an epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">Id of the epic.</param>
/// <param name="options">Notes retrieval options.</param>
/// <returns>Epic satisfying options.</returns>
public async Task<IList<Note>> GetNotesAsync(GroupId groupId, int epicId, Action<NotesQueryOptions> options = null)
{
var queryOptions = new NotesQueryOptions();
options?.Invoke(queryOptions);

string url = _notesQueryBuilder.Build($"groups/{groupId}/epics/{epicId}/notes", queryOptions);
return await _httpFacade.GetPagedList<Note>(url);
}
/// <summary>
/// Retrieves issues linked to an epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">Id of the epic.</param>
/// <param name="options">Issues retrieval options.</param>
/// <returns>Epic satisfying options.</returns>
public async Task<IList<Issue>> GetIssusAsync(GroupId groupId, int epicId, Action<IssuesQueryOptions> options = null)
{
var queryOptions = new IssuesQueryOptions();
options?.Invoke(queryOptions);

string url = _issuesQueryBuilder.Build($"groups/{groupId}/epics/{epicId}/issues", queryOptions);
return await _httpFacade.GetPagedList<Issue>(url);
}

/// <summary>
/// Creates a new note (comment) to a single epic.
/// </summary>
/// <returns>The newly created epic note.</returns>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicIid">The IID of an epic.</param>
/// <param name="request">Create epic note request.</param>
public async Task<Note> CreateNoteAsync(GroupId groupId, int epicId, CreateNoteRequest request) =>
await _httpFacade.Post<Note>($"groups/{groupId}/epics/{epicId}/notes", request);


/// <summary>
/// Get a list of visible epics for a group of the authenticated user.
/// </summary>
/// <param name="options">Query options.</param>
public async Task<IList<Epic>> GetAsync(GroupId groupId, Action<EpicsGroupQueryOptions> options = null)
{
var queryOptions = new EpicsGroupQueryOptions();
options?.Invoke(queryOptions);

string url = _queryBuilder.Build($"groups/{groupId}/epics", queryOptions);
return await _httpFacade.GetPagedList<Epic>(url);
}

/// <summary>
/// Assigns an issue to an epic
/// </summary>
/// <returns>Assigned issue</returns>
public async Task<Issue> AssignIssueAsync(GroupId groupId, int epicId, int issueId) =>
await _httpFacade.Post<Issue>($"groups/{groupId}/epics/{epicId}/issues/{issueId}");

/// <summary>
/// Updates an epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">The ID of an epic.</param>
/// <param name="request">Update epic request.</param>
/// <returns>The updated epic.</returns>
public async Task<Epic> UpdateAsync(GroupId groupId, int epicId, UpdateEpicRequest request) =>
await _httpFacade.Put<Epic>($"groups/{groupId}/epics/{epicId}", request);
}
}
6 changes: 4 additions & 2 deletions src/GitLabApiClient/GitLabApiClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Copyright />
<Description>GitLabApiClient is a .NET rest client for GitLab API v4.</Description>
<Authors>nmklotas</Authors>
<Authors>nmklotas (mhobl)</Authors>
<PackageProjectUrl>https://github.com/nmklotas/GitLabApiClient</PackageProjectUrl>
<RepositoryUrl>https://github.com/nmklotas/GitLabApiClient</RepositoryUrl>
<PackageTags>GitLab REST API CI Client</PackageTags>
Expand All @@ -16,10 +16,12 @@
<IncludeSymbols>true</IncludeSymbols>
<UseFullSemVerForNuGet>true</UseFullSemVerForNuGet>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
</PropertyGroup>

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

Expand Down
16 changes: 11 additions & 5 deletions src/GitLabApiClient/GitLabClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
clientTimeout);

var projectQueryBuilder = new ProjectsQueryBuilder();
var projectIssueNotesQueryBuilder = new ProjectIssueNotesQueryBuilder();
var projectMergeRequestsNotesQueryBuilder = new ProjectMergeRequestsNotesQueryBuilder();
var notesQueryBuilder = new NotesQueryBuilder();
var issuesQueryBuilder = new IssuesQueryBuilder();
var mergeRequestsQueryBuilder = new MergeRequestsQueryBuilder();
var projectMilestonesQueryBuilder = new MilestonesQueryBuilder();
var projectMergeRequestsQueryBuilder = new ProjectMergeRequestsQueryBuilder();
var groupsQueryBuilder = new GroupsQueryBuilder();
var groupLabelsQueryBuilder = new GroupLabelsQueryBuilder();
var projectsGroupsQueryBuilder = new ProjectsGroupQueryBuilder();
var epicsGroupQueryBuilder = new EpicsGroupQueryBuilder();
var branchQueryBuilder = new BranchQueryBuilder();
var releaseQueryBuilder = new ReleaseQueryBuilder();
var tagQueryBuilder = new TagQueryBuilder();
Expand All @@ -60,12 +60,13 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
var jobQueryBuilder = new JobQueryBuilder();
var toDoListBuilder = new ToDoListQueryBuilder();

Issues = new IssuesClient(_httpFacade, issuesQueryBuilder, projectIssueNotesQueryBuilder);
Issues = new IssuesClient(_httpFacade, issuesQueryBuilder, notesQueryBuilder);
Uploads = new UploadsClient(_httpFacade);
MergeRequests = new MergeRequestsClient(_httpFacade, mergeRequestsQueryBuilder, projectMergeRequestsQueryBuilder, projectMergeRequestsNotesQueryBuilder);
MergeRequests = new MergeRequestsClient(_httpFacade, mergeRequestsQueryBuilder, projectMergeRequestsQueryBuilder, notesQueryBuilder);
Projects = new ProjectsClient(_httpFacade, projectQueryBuilder, projectMilestonesQueryBuilder, jobQueryBuilder);
Users = new UsersClient(_httpFacade);
Groups = new GroupsClient(_httpFacade, groupsQueryBuilder, projectsGroupsQueryBuilder, projectMilestonesQueryBuilder, groupLabelsQueryBuilder);
Groups = new GroupsClient(_httpFacade, groupsQueryBuilder, projectsGroupsQueryBuilder, projectMilestonesQueryBuilder, groupLabelsQueryBuilder, epicsGroupQueryBuilder);
Epics = new EpicsClient(_httpFacade, epicsGroupQueryBuilder, notesQueryBuilder, issuesQueryBuilder);
Branches = new BranchClient(_httpFacade, branchQueryBuilder);
Releases = new ReleaseClient(_httpFacade, releaseQueryBuilder);
Tags = new TagClient(_httpFacade, tagQueryBuilder);
Expand Down Expand Up @@ -110,6 +111,11 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
/// </summary>
public IGroupsClient Groups { get; }

/// <summary>
/// Access GitLab's epics API.
/// </summary>
public IEpicsClient Epics { get; }

/// <summary>
/// Access GitLab's branches API.
/// </summary>
Expand Down
22 changes: 21 additions & 1 deletion src/GitLabApiClient/GroupsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using GitLabApiClient.Internal.Queries;
using GitLabApiClient.Internal.Utilities;
using GitLabApiClient.Models;
using GitLabApiClient.Models.Epics.Responses;
using GitLabApiClient.Models.Groups.Requests;
using GitLabApiClient.Models.Groups.Responses;
using GitLabApiClient.Models.Milestones.Requests;
Expand All @@ -28,19 +29,22 @@ public sealed class GroupsClient : IGroupsClient
private readonly ProjectsGroupQueryBuilder _projectsQueryBuilder;
private readonly MilestonesQueryBuilder _queryMilestonesBuilder;
private readonly GroupLabelsQueryBuilder _queryGroupLabelBuilder;
private readonly EpicsGroupQueryBuilder _epicsGroupQueryBuilder;

internal GroupsClient(
GitLabHttpFacade httpFacade,
GroupsQueryBuilder queryBuilder,
ProjectsGroupQueryBuilder projectsQueryBuilder,
MilestonesQueryBuilder queryMilestonesBuilder,
GroupLabelsQueryBuilder queryGroupLabelBuilder)
GroupLabelsQueryBuilder queryGroupLabelBuilder,
EpicsGroupQueryBuilder epicsGroupQueryBuilder)
{
_httpFacade = httpFacade;
_queryBuilder = queryBuilder;
_projectsQueryBuilder = projectsQueryBuilder;
_queryMilestonesBuilder = queryMilestonesBuilder;
_queryGroupLabelBuilder = queryGroupLabelBuilder;
_epicsGroupQueryBuilder = epicsGroupQueryBuilder;
}

/// <summary>
Expand Down Expand Up @@ -96,6 +100,22 @@ public async Task<IList<Project>> GetProjectsAsync(GroupId groupId, Action<Proje
return await _httpFacade.GetPagedList<Project>(url);
}

/// <summary>
/// Get a list of epics in this group.
/// When accessed without authentication, only public epics are returned.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="options">Epics projects retrieval options.</param>
/// <returns>Epics satisfying options.</returns>
public async Task<IList<Epic>> GetEpicsAsync(GroupId groupId, Action<EpicsGroupQueryOptions> options = null)
{
var queryOptions = new EpicsGroupQueryOptions();
options?.Invoke(queryOptions);

string url = _epicsGroupQueryBuilder.Build($"groups/{groupId}/epics", queryOptions);
return await _httpFacade.GetPagedList<Epic>(url);
}

/// <summary>
/// Get a list of members in this group.
/// </summary>
Expand Down
80 changes: 80 additions & 0 deletions src/GitLabApiClient/IEpicsClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Models.Epics.Requests;
using GitLabApiClient.Models.Epics.Responses;
using GitLabApiClient.Models.Groups.Requests;
using GitLabApiClient.Models.Issues.Requests;
using GitLabApiClient.Models.Issues.Responses;
using GitLabApiClient.Models.Notes.Requests;
using GitLabApiClient.Models.Notes.Responses;

namespace GitLabApiClient
{
public interface IEpicsClient
{
/// <summary>
/// Retrieves epic by its id, path or <see cref="Epic"/>.
/// </summary>
/// <param name="epicId">The ID, path or <see cref="Epic"/> of the epic.</param>
Task<Epic> GetAsync(GroupId groupId, int epicId);

/// <summary>
/// Get a list of visible epics for a group of the authenticated user.
/// </summary>
/// <param name="options">Query options.</param>
Task<IList<Epic>> GetAsync(GroupId groupId, Action<EpicsGroupQueryOptions> options = null);

/// <summary>
/// Retrieves notes (comments) of an epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">Id of the epic.</param>
/// <param name="options">Notes retrieval options.</param>
/// <returns>Epic satisfying options.</returns>
Task<IList<Note>> GetNotesAsync(GroupId groupId, int epicId, Action<NotesQueryOptions> options = null);

/// <summary>
/// Retrieves issues linked to an epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">Id of the epic.</param>
/// <param name="options">Issues retrieval options.</param>
/// <returns>Epic satisfying options.</returns>
Task<IList<Issue>> GetIssusAsync(GroupId groupId, int epicId, Action<IssuesQueryOptions> options = null);

/// <summary>
/// Creates a new epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="request">Create epic request.</param>
/// <returns>Newly created epic.</returns>
Task<Epic> CreateAsync(GroupId groupId, CreateEpicRequest request);

/// <summary>
/// Creates a new note (comment) to a single epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">The ID of an epic.</param>
/// <param name="request">Create epic note request.</param>
/// <returns>The newly created epic note.</returns>
Task<Note> CreateNoteAsync(GroupId groupId, int epicId, CreateNoteRequest request);

/// <summary>
/// Assigns an issue to an epic
/// </summary>
/// <returns>Assigned issue</returns>
Task<Issue> AssignIssueAsync(GroupId groupId, int epicId, int issueId);

/// <summary>
/// Updates an epic.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="epicId">The ID of an epic.</param>
/// <param name="request">Update epic request.</param>
/// <returns>The updated epic.</returns>
Task<Epic> UpdateAsync(GroupId groupId, int epicId, UpdateEpicRequest request);
}
}
13 changes: 12 additions & 1 deletion src/GitLabApiClient/IGroupsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Models;
using GitLabApiClient.Models.Epics.Responses;
using GitLabApiClient.Models.Groups.Requests;
using GitLabApiClient.Models.Groups.Responses;
using GitLabApiClient.Models.Milestones.Requests;
Expand Down Expand Up @@ -47,9 +48,18 @@ public interface IGroupsClient
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="options">Groups projects retrieval options.</param>
/// <returns>Issues satisfying options.</returns>
/// <returns>Projecs satisfying options.</returns>
Task<IList<Project>> GetProjectsAsync(GroupId groupId, Action<ProjectsGroupQueryOptions> options = null);

/// <summary>
/// Get a list of epics in this group.
/// When accessed without authentication, only public epics are returned.
/// </summary>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="options">Epics projects retrieval options.</param>
/// <returns>Epics satisfying options.</returns>
Task<IList<Epic>> GetEpicsAsync(GroupId groupId, Action<EpicsGroupQueryOptions> options = null);

/// <summary>
/// Get a list of members in this group.
/// </summary>
Expand Down Expand Up @@ -254,5 +264,6 @@ Task<IList<GroupLabel>> GetLabelsAsync(GroupId groupId,
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="key">The Key ID of the variable.</param>
Task DeleteVariableAsync(GroupId groupId, string key);

}
}
13 changes: 11 additions & 2 deletions src/GitLabApiClient/IIssuesClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public interface IIssuesClient
/// <param name="issueIid">Iid of the issue.</param>
/// <param name="options">IssueNotes retrieval options.</param>
/// <returns>Issues satisfying options.</returns>
Task<IList<Note>> GetNotesAsync(ProjectId projectId, int issueIid, Action<IssueNotesQueryOptions> options = null);
Task<IList<Note>> GetNotesAsync(ProjectId projectId, int issueIid, Action<NotesQueryOptions> options = null);

/// <summary>
/// Creates new issue.
Expand All @@ -107,7 +107,16 @@ public interface IIssuesClient
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="issueIid">The IID of an issue.</param>
/// <param name="request">Create issue note request.</param>
Task<Note> CreateNoteAsync(ProjectId projectId, int issueIid, CreateIssueNoteRequest request);
Task<Note> CreateNoteAsync(ProjectId projectId, int issueIid, CreateNoteRequest request);

/// <summary>
/// Moves an issues to a new project
/// </summary>
/// <returns>The newly created issue note.</returns>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="issueIid">The IID of an issue.</param>
/// <param name="request">Create issue note request.</param>
Task<Issue> MoveIssueAsync(ProjectId projectId, int issueIid, MoveIssueRequest request);

/// <summary>
/// Updated existing issue.
Expand Down
Loading