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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ PublishScripts/
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/

# Do not ignore packages API!
!**/Models/Packages/*

# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
Expand Down
7 changes: 7 additions & 0 deletions src/GitLabApiClient/GitLabClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
var projectIssueNotesQueryBuilder = new ProjectIssueNotesQueryBuilder();
var projectMergeRequestsNotesQueryBuilder = new ProjectMergeRequestsNotesQueryBuilder();
var issuesQueryBuilder = new IssuesQueryBuilder();
var packagesQueryBuilder = new PackagesQueryBuilder();
var mergeRequestsQueryBuilder = new MergeRequestsQueryBuilder();
var projectMilestonesQueryBuilder = new MilestonesQueryBuilder();
var projectMergeRequestsQueryBuilder = new ProjectMergeRequestsQueryBuilder();
Expand Down Expand Up @@ -76,6 +77,7 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
Pipelines = new PipelineClient(_httpFacade, pipelineQueryBuilder, jobQueryBuilder);
Trees = new TreesClient(_httpFacade, treeQueryBuilder);
Files = new FilesClient(_httpFacade);
Packages = new PackagesClient(_httpFacade, packagesQueryBuilder);
Runners = new RunnersClient(_httpFacade);
ToDoList = new ToDoListClient(_httpFacade, toDoListBuilder);
Iterations = new IterationsClient(_httpFacade, iterationsBuilder);
Expand Down Expand Up @@ -147,6 +149,11 @@ public GitLabClient(string hostUrl, string authenticationToken = "", HttpMessage
/// </summary>
public IFilesClient Files { get; }

/// <summary>
/// Access GitLab's packages API.
/// </summary>
public IPackagesClient Packages { get; }

/// <summary>
/// Access GitLab's Markdown API.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/GitLabApiClient/IGitLabClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public interface IGitLabClient
/// </summary>
IFilesClient Files { get; }

/// <summary>
/// Access GitLab's packages API.
/// </summary>
IPackagesClient Packages { get; }

/// <summary>
/// Access GitLab's Markdown API.
/// </summary>
Expand Down
61 changes: 61 additions & 0 deletions src/GitLabApiClient/IPackagesClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitLabApiClient.Internal.Paths;
using GitLabApiClient.Models.Packages.Responses;
using GitLabApiClient.Models.Packages.Requests;
using GitLabApiClient.Models.Uploads.Requests;

namespace GitLabApiClient
{
public interface IPackagesClient
{

/// <summary>
/// Pyblish a generic package file. When you publish a package file, if the package does not exist, it is created.
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="packageId">The ID, path or <see cref="Package"/> of the package.</param>
/// <param name="uploadRequest">The upload request containing the filename and stream to be uploaded</param>
Task UploadFileAsync(ProjectId projectId, string packageName, string packageVersion, string fileName, CreateUploadRequest uploadRequest, bool hidden = false);


/// <summary>
/// Download a generic package file.
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="outputPath">The filename that should contain the contents of the download after the download completes</param>
/// <returns>Status of the export</returns>
Task DownloadFileAsync(ProjectId projectId, string packageName, string packageVersion, string fileName, string outputPath);

/// <summary>
/// Retrieves project package.
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="packageId">The ID, path or <see cref="Package"/> of the package.</param>
Task<Package> GetAsync(ProjectId projectId, int packageId);


/// <summary>
/// List package files
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="packageId">The ID, path or <see cref="Package"/> of the package.</param>
Task<IList<PackageFile>> GetPackageFilesAsync(ProjectId projectId, int packageId);

/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="groupId">The ID, path or <see cref="Group"/> of the group.</param>
/// <param name="options">Packages retrieval options.</param>
/// <returns>Packages satisfying options.</returns>
Task<IList<Package>> GetAllAsync(ProjectId projectId = null, GroupId groupId = null, Action<PackagesQueryOptions> options = null);


/// <summary>
/// Delete a package.
/// </summary>
/// <param name="projectId">The ID, path or <see cref="Project"/> of the project.</param>
/// <param name="packageId">The ID, path or <see cref="Package"/> of the package.</param>
Task DeletePackageAsync(ProjectId projectId, int packageId);

}
}
3 changes: 3 additions & 0 deletions src/GitLabApiClient/Internal/Http/GitLabHttpFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public Task<T> Put<T>(string uri, object data) =>
public Task Put(string uri, object data) =>
_requestor.Put(uri, data);

public Task PutFileBody(string uri, CreateUploadRequest uploadRequest) =>
_requestor.PutFileBody(uri, uploadRequest);

public Task Delete(string uri) =>
_requestor.Delete(uri);
public Task Delete(string uri, object data) =>
Expand Down
7 changes: 7 additions & 0 deletions src/GitLabApiClient/Internal/Http/GitlabApiRequestor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ public async Task Put(string url, object data)
await EnsureSuccessStatusCode(responseMessage);
}

public async Task PutFileBody(string url, CreateUploadRequest uploadRequest)
{
var content = new StreamContent(uploadRequest.Stream);
var responseMessage = await _client.PutAsync(url, content);
await EnsureSuccessStatusCode(responseMessage);
}

public async Task Delete(string url)
{
var responseMessage = await _client.DeleteAsync(url);
Expand Down
69 changes: 69 additions & 0 deletions src/GitLabApiClient/Internal/Queries/PackagesQueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Linq;
using GitLabApiClient.Internal.Utilities;
using GitLabApiClient.Models;
using GitLabApiClient.Models.Packages.Requests;
using GitLabApiClient.Models.Packages.Responses;

namespace GitLabApiClient.Internal.Queries
{
internal class PackagesQueryBuilder : QueryBuilder<PackagesQueryOptions>
{
protected override void BuildCore(Query query, PackagesQueryOptions options)
{
string stateQueryValue = GetStatusQueryValue(options.Status);
if (!stateQueryValue.IsNullOrEmpty())
query.Add("status", stateQueryValue);

string packageTypeQueryValue = GetPackageTypeQueryValue(options.PackageType);
if (!packageTypeQueryValue.IsNullOrEmpty())
query.Add("package_type", packageTypeQueryValue);

if (!string.IsNullOrEmpty(options.PackageName))
query.Add("package_name", options.PackageName);

if (options.Order != PackagesOrder.CreatedAt)
query.Add("order_by", GetPackagesOrderQueryValue(options.Order));

if (options.SortOrder != SortOrder.Descending)
query.Add("sort", GetSortOrderQueryValue(options.SortOrder));

if (options.IncludeVersionless)
query.Add("include_versionless", true);
}

private static string GetPackageTypeQueryValue(PackageType type) => type == PackageType.All ? "" : type.ToString().ToLower();

private static string GetStatusQueryValue(PackageStatus status)
{
switch (status)
{
case PackageStatus.Default:
return "";
case PackageStatus.Hidden:
return "hidden";
case PackageStatus.Processing:
return "processing";
default:
throw new NotSupportedException($"Status {status} is not supported");
}
}

private static string GetPackagesOrderQueryValue(PackagesOrder order)
{
switch (order)
{
case PackagesOrder.CreatedAt:
return "created_at";
case PackagesOrder.Name:
return "name";
case PackagesOrder.Version:
return "version";
case PackagesOrder.Type:
return "type";
default:
throw new NotSupportedException($"Order {order} is not supported");
}
}
}
}
10 changes: 10 additions & 0 deletions src/GitLabApiClient/Models/Issues/Requests/PackagesOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace GitLabApiClient.Models.Packages.Requests
{
public enum PackagesOrder
{
CreatedAt,
Name,
Version,
Type
}
}
9 changes: 9 additions & 0 deletions src/GitLabApiClient/Models/Issues/Responses/PackageStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace GitLabApiClient.Models.Packages.Responses
{
public enum PackageStatus
{
Default,
Hidden,
Processing
}
}
15 changes: 15 additions & 0 deletions src/GitLabApiClient/Models/Issues/Responses/PackageType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace GitLabApiClient.Models.Packages.Responses
{
public enum PackageType
{
All,
Conan,
Maven,
Npm,
PyPi,
Composer,
Nuget,
Helm,
Golang
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using GitLabApiClient.Models.Packages.Responses;

namespace GitLabApiClient.Models.Packages.Requests
{
/// <summary>
/// Options for issues listing
/// </summary>
public class PackagesQueryOptions
{
internal PackagesQueryOptions() { }


/// <summary>
/// Return all packages, or packages with a specific status
/// Default is Default.
/// </summary>
public PackageStatus Status { get; set; }

/// <summary>
/// Filter the returned packages by type. One of conan, maven, npm, pypi, composer, nuget, helm, or golang. (Introduced in GitLab 12.9)
/// Defaults to packages of all types. (Introduced in GitLab 9.5).
/// </summary>
public PackageType PackageType { get; set; }

/// <summary>
/// Filter the project packages with a fuzzy search by name. (Introduced in GitLab 12.9)
/// </summary>
public string PackageName { get; set; }


/// <summary>
/// Specifies issues order. Default is Creation time.
/// </summary>
public PackagesOrder Order { get; set; }

/// <summary>
/// Specifies project sort order. Default is descending.
/// </summary>
public SortOrder SortOrder { get; set; }

/// <summary>
/// When set to true, versionless packages are included in the response. (Introduced in GitLab 13.8)
/// </summary>
public bool IncludeVersionless { get; set; } = false;
}
}
53 changes: 53 additions & 0 deletions src/GitLabApiClient/Models/Packages/Responses/Package.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using Newtonsoft.Json;


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

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

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

[JsonProperty("version")]
public string Version { get; set; }

[JsonProperty("package_type")]
public string PackageType { get; set; }

}

public sealed class PackageFile
{
[JsonProperty("id")]
public int Id { get; set; }

[JsonProperty("package_id")]
public string PackageId { get; set; }

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

[JsonProperty("file_name")]
public string FileName { get; set; }

[JsonProperty("size")]
public int Size { get; set; }

[JsonProperty("file_md5")]
public string FileMD5 { get; set; }

[JsonProperty("file_sha1")]
public string FileSHA1 { get; set; }

[JsonProperty("file_sha256")]
public string FileSHA256 { get; set; }

}
}
Loading