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

feat(referrers): support referrers API #180

Merged
merged 47 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e3e1217
push manifest with subject
Nov 18, 2024
846e173
add unit tests
Nov 19, 2024
7fca0cb
add unit tests
Nov 19, 2024
ec93662
Merge branch 'main' into feature/pushManifestWithSubject
Nov 19, 2024
7809549
resolve merge conflicts
Nov 19, 2024
c7e4418
add tests
Nov 19, 2024
a6d552f
add comments
Nov 19, 2024
685ab70
add unit test
Nov 20, 2024
1b9ade3
add unit tests
Nov 20, 2024
5041592
resolve comments
Nov 21, 2024
c26ccb6
add SetReferrersSupportLevel func and unit tests
Nov 21, 2024
ddbf048
remove NoReferrerUpdateException and update tests accordingly
Nov 22, 2024
d6e8499
add Index constructor
Nov 24, 2024
cf431f0
add license header
Nov 26, 2024
50e696e
resolve merge conflicts
Nov 26, 2024
856c0ef
add lock on SetReferrerState
Nov 29, 2024
fcb121e
simplify ApplyReferrerChanges
Nov 29, 2024
2b24e07
resolve comments
Dec 3, 2024
7df36ca
Merge branch 'main' into feature/pushManifestWithSubject
Dec 3, 2024
c30d6b2
resolve comments
Dec 13, 2024
b20a202
resolve comments
Dec 20, 2024
07d8e06
resolve comments
Dec 23, 2024
27382ae
resolve comments
Dec 23, 2024
b858999
Merge branch 'main' into feature/pushManifestWithSubject
Dec 23, 2024
404337e
resolve comments
Dec 23, 2024
1041bc0
resolve comments
Dec 23, 2024
85435cc
list referrers
Jan 10, 2025
cd05c4b
fix merge conflict
Jan 12, 2025
e17c50c
add unit tests
Jan 13, 2025
db582c2
add unit tests
Jan 15, 2025
966b2ad
add comments
Feb 3, 2025
037b092
format codes
Feb 3, 2025
71fcfcb
add headers
Feb 3, 2025
dfb1291
Merge branch 'main' into feature/listReferrers
Feb 5, 2025
447a280
add invalidResponseException tests
Feb 5, 2025
f668c22
Merge branch 'main' into feature/listReferrers
Feb 10, 2025
7f0553f
Merge branch 'main' into feature/listReferrers
Feb 18, 2025
7724d7f
address comments
Feb 19, 2025
9f1cc15
address comments
Feb 19, 2025
c64338f
verify returned manifest
Feb 24, 2025
9880d45
change callback function to return IAsyncEnumerable
Feb 25, 2025
703df70
resolve conflicts
Feb 25, 2025
b923532
resolve comments
Feb 26, 2025
5a51f41
resolve comments
Feb 26, 2025
b98b303
resolve comments
Feb 26, 2025
8c7b38e
resolve comments
Feb 26, 2025
28d3be2
resolve comments
Feb 26, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
namespace OrasProject.Oras.Exceptions;

/// <summary>
/// InvalidReferenceException is thrown when the reference is invlid
/// InvalidReferenceException is thrown when the reference is invalid.
/// </summary>
public class InvalidReferenceException : FormatException
{
Expand Down
36 changes: 36 additions & 0 deletions src/OrasProject.Oras/Exceptions/InvalidResponseException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright The ORAS Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;

namespace OrasProject.Oras.Exceptions;

/// <summary>
/// InvalidResponseException is thrown when the response is invalid.
/// </summary>
public class InvalidResponseException : FormatException
{
public InvalidResponseException()
{
}

public InvalidResponseException(string? message)
: base(message)
{
}

public InvalidResponseException(string? message, Exception? inner)
: base(message, inner)
{
}
}
2 changes: 1 addition & 1 deletion src/OrasProject.Oras/Registry/Reference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public static bool TryParse(string reference, [NotNullWhen(true)] out Reference?
return false;
}
}

public Reference(Reference other)
{
if (other == null)
Expand Down
32 changes: 1 addition & 31 deletions src/OrasProject.Oras/Registry/Remote/ManifestStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
using OrasProject.Oras.Exceptions;
using OrasProject.Oras.Oci;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Net;
using System.Net.Http;
Expand All @@ -29,7 +27,7 @@

public class ManifestStore(Repository repository) : IManifestStore
{
public Repository Repository { get; init; } = repository;

Check warning on line 30 in src/OrasProject.Oras/Registry/Remote/ManifestStore.cs

View workflow job for this annotation

GitHub Actions / Analyze (8.0.x)

Parameter 'Repository repository' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

Check warning on line 30 in src/OrasProject.Oras/Registry/Remote/ManifestStore.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x)

Parameter 'Repository repository' is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.

/// <summary>
/// Fetches the content identified by the descriptor.
Expand Down Expand Up @@ -274,7 +272,7 @@
{
// 1. pull the original referrers index list using referrers tag schema
var referrersTag = Referrers.BuildReferrersTag(subject);
var (oldDesc, oldReferrers) = await PullReferrersIndexList(referrersTag, cancellationToken).ConfigureAwait(false);
var (oldDesc, oldReferrers) = await Repository.PullReferrersIndexList(referrersTag, cancellationToken).ConfigureAwait(false);

// 2. apply the referrer change to referrers list
var (updatedReferrers, updateRequired) =
Expand Down Expand Up @@ -306,37 +304,9 @@
}

// 4. delete the dangling original referrers index, if applicable
await DeleteAsync(oldDesc, cancellationToken).ConfigureAwait(false);

Check warning on line 307 in src/OrasProject.Oras/Registry/Remote/ManifestStore.cs

View workflow job for this annotation

GitHub Actions / Analyze (8.0.x)

Possible null reference argument for parameter 'target' in 'Task ManifestStore.DeleteAsync(Descriptor target, CancellationToken cancellationToken = default(CancellationToken))'.

Check warning on line 307 in src/OrasProject.Oras/Registry/Remote/ManifestStore.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x)

Possible null reference argument for parameter 'target' in 'Task ManifestStore.DeleteAsync(Descriptor target, CancellationToken cancellationToken = default(CancellationToken))'.
}

/// <summary>
/// PullReferrersIndexList retrieves the referrers index list associated with the given referrers tag.
/// It fetches the index manifest from the repository, deserializes it into an `Index` object,
/// and returns the descriptor along with the list of manifests (referrers). If the referrers index is not found,
/// an empty descriptor and an empty list are returned.
/// </summary>
/// <param name="referrersTag"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
internal async Task<(Descriptor?, IList<Descriptor>)> PullReferrersIndexList(String referrersTag, CancellationToken cancellationToken = default)
{
try
{
var (desc, content) = await FetchAsync(referrersTag, cancellationToken).ConfigureAwait(false);
var index = JsonSerializer.Deserialize<Index>(content);
if (index == null)
{
throw new JsonException($"null index manifests list when pulling referrers index list for referrers tag {referrersTag}");
}
return (desc, index.Manifests);
}
catch (NotFoundException)
{
return (null, ImmutableArray<Descriptor>.Empty);
}
}


/// <summary>
/// Pushes the manifest content, matching the expected descriptor.
/// </summary>
Expand Down
37 changes: 37 additions & 0 deletions src/OrasProject.Oras/Registry/Remote/Referrers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// limitations under the License.

using System.Collections.Generic;
using System.Linq;
using OrasProject.Oras.Content;
using OrasProject.Oras.Oci;

Expand Down Expand Up @@ -105,4 +106,40 @@ internal static (IList<Descriptor>, bool) ApplyReferrerChanges(IList<Descriptor>

return (updatedReferrers, updateRequired);
}

/// <summary>
/// IsReferrersFilterApplied checks if requstedFilter is in the applied filters list.
/// </summary>
/// <param name="appliedFilters"></param>
/// <param name="requestedFilter"></param>
/// <returns></returns>
internal static bool IsReferrersFilterApplied(string? appliedFilters, string requestedFilter) {
if (string.IsNullOrEmpty(appliedFilters) || string.IsNullOrEmpty(requestedFilter))
{
return false;
}

var filters = appliedFilters.Split(",");
foreach (var filter in filters)
{
if (filter == requestedFilter)
{
return true;
}
}

return false;
}

/// <summary>
/// FilterReferrers filters out a list of referrers based on the specified artifact type
/// </summary>
/// <param name="referrers"></param>
/// <param name="artifactType"></param>
/// <returns></returns>
internal static IList<Descriptor> FilterReferrers(IList<Descriptor> referrers, string? artifactType)
{
return string.IsNullOrEmpty(artifactType) ? referrers : referrers.Where(referrer => referrer.ArtifactType == artifactType).ToList();
}
}

Loading
Loading