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

Rework support for @latest version #752

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/LibraryManager/ManifestConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@ public static class ManifestConstants
/// libman.json files element
/// </summary>
public const string Files = "files";

/// <summary>
/// For providers that support versioned libraries, this represents the evergreen latest version
/// </summary>
public const string LatestVersion = "latest";
}
}
12 changes: 12 additions & 0 deletions src/LibraryManager/Providers/BaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ public virtual async Task<ILibraryOperationResult> UpdateStateAsync(ILibraryInst
try
{
ILibraryCatalog catalog = GetCatalog();

if (string.Equals(desiredState.Version, ManifestConstants.LatestVersion, StringComparison.Ordinal))
{
// replace the @latest version with the latest version from the catalog. This redirect
// ensures that as new versions are released, we will not reuse stale "latest" assets
// from the cache.
string latestVersion = await catalog.GetLatestVersion(libraryId, includePreReleases: false, cancellationToken).ConfigureAwait(false);
LibraryInstallationState newState = LibraryInstallationState.FromInterface(desiredState);
newState.Version = latestVersion;
desiredState = newState;
}

ILibrary library = await catalog.GetLibraryAsync(desiredState.Name, desiredState.Version, cancellationToken).ConfigureAwait(false);

if (library == null)
Expand Down
12 changes: 9 additions & 3 deletions src/LibraryManager/Providers/Cdnjs/CdnjsCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class CdnjsCatalog : ILibraryCatalog
// TO DO: These should become Provider properties to be passed to CacheService
private const string FileName = "cache.json";
public const string CatalogUrl = "https://api.cdnjs.com/libraries?fields=name,description,version";
public const string MetaPackageUrlFormat = "https://api.cdnjs.com/libraries/{0}?fields=filename,versions"; // {libraryName}
public const string MetaPackageUrlFormat = "https://api.cdnjs.com/libraries/{0}?fields=filename,versions"; // {libraryName}
public const string PackageVersionUrlFormat = "https://api.cdnjs.com/libraries/{0}/{1}?fields=files"; // {libraryName}/{version}

private readonly string _cacheFile;
Expand Down Expand Up @@ -150,7 +150,13 @@ public async Task<ILibrary> GetLibraryAsync(string libraryName, string version,
throw new InvalidLibraryException(libraryId, _provider.Id);
}

if (!(await GetLibraryVersionsAsync(libraryName, cancellationToken)).Contains(version))
if (string.Equals(version, ManifestConstants.LatestVersion, StringComparison.Ordinal))
{
version = await GetLatestVersion(libraryName, includePreReleases: false, cancellationToken);
}

IEnumerable<string> enumerable = await GetLibraryVersionsAsync(libraryName, cancellationToken);
if (!enumerable.Contains(version))
{
throw new InvalidLibraryException(libraryId, _provider.Id);
}
Expand All @@ -160,7 +166,7 @@ public async Task<ILibrary> GetLibraryAsync(string libraryName, string version,
JObject groupMetadata = await GetLibraryGroupMetadataAsync(libraryName, cancellationToken);
string defaultFile = groupMetadata?["filename"].Value<string>() ?? string.Empty;

IEnumerable<string> libraryFiles= await GetLibraryFilesAsync(libraryName, version, cancellationToken).ConfigureAwait(false);
IEnumerable<string> libraryFiles = await GetLibraryFilesAsync(libraryName, version, cancellationToken).ConfigureAwait(false);

return new CdnjsLibrary
{
Expand Down
9 changes: 4 additions & 5 deletions src/LibraryManager/Providers/Unpkg/UnpkgCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ internal class UnpkgCatalog : ILibraryCatalog
public const string CacheFileName = "cache.json";
public const string LibraryFileListUrlFormat = "https://unpkg.com/{0}@{1}/?meta"; // e.g. https://unpkg.com/jquery@3.3.1/?meta
public const string LatestLibraryVersonUrl = "https://unpkg.com/{0}/package.json"; // e.g. https://unpkg.com/jquery/package.json
public const string LatestVersionTag = "latest";

private readonly INpmPackageInfoFactory _packageInfoFactory;
private readonly INpmPackageSearch _packageSearch;
Expand Down Expand Up @@ -58,7 +57,7 @@ public async Task<string> GetLatestVersion(string libraryName, bool includePreRe
try
{
string latestLibraryVersionUrl = string.Format(LatestLibraryVersonUrl, libraryName);
string latestCacheFile = Path.Combine(_cacheFolder, libraryName, $"{LatestVersionTag}.json");
string latestCacheFile = Path.Combine(_cacheFolder, libraryName, $"{ManifestConstants.LatestVersion}.json");

string latestJson = await _cacheService.GetContentsFromUriWithCacheFallbackAsync(latestLibraryVersionUrl,
latestCacheFile,
Expand Down Expand Up @@ -88,7 +87,7 @@ public async Task<ILibrary> GetLibraryAsync(string libraryName, string version,
}

string libraryId = _libraryNamingScheme.GetLibraryId(libraryName, version);
if (string.Equals(version, LatestVersionTag, StringComparison.Ordinal))
if (string.Equals(version, ManifestConstants.LatestVersion, StringComparison.Ordinal))
{
string latestVersion = await GetLatestVersion(libraryId, includePreReleases: false, cancellationToken).ConfigureAwait(false);
libraryId = _libraryNamingScheme.GetLibraryId(libraryName, latestVersion);
Expand Down Expand Up @@ -263,8 +262,8 @@ public async Task<CompletionSet> GetLibraryCompletionSetAsync(string libraryName
// support @latest version
completions.Add(new CompletionItem
{
DisplayText = LatestVersionTag,
InsertionText = _libraryNamingScheme.GetLibraryId(name, LatestVersionTag),
DisplayText = ManifestConstants.LatestVersion,
InsertionText = _libraryNamingScheme.GetLibraryId(name, ManifestConstants.LatestVersion),
});

completionSet.CompletionType = CompletionSortOrder.Version;
Expand Down
9 changes: 4 additions & 5 deletions src/LibraryManager/Providers/jsDelivr/JsDelivrCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ internal class JsDelivrCatalog : ILibraryCatalog
public const string LatestLibraryVersionUrl = "https://data.jsdelivr.com/v1/package/npm/{0}";
public const string LibraryFileListUrlFormatGH = "https://data.jsdelivr.com/v1/package/gh/{0}/flat";
public const string LatestLibraryVersionUrlGH = "https://data.jsdelivr.com/v1/package/gh/{0}";
public const string LatestVersionTag = "latest";

private readonly INpmPackageInfoFactory _packageInfoFactory;
private readonly INpmPackageSearch _packageSearch;
Expand Down Expand Up @@ -61,7 +60,7 @@ public async Task<string> GetLatestVersion(string libraryId, bool includePreRele
bool isGitHub = IsGitHub(libraryId);
string latestLibraryVersionUrl = string.Format(isGitHub ? LatestLibraryVersionUrlGH : LatestLibraryVersionUrl, name);
string cacheFileType = isGitHub ? "github" : "npm";
string latestLibraryVersionCacheFile = Path.Combine(_cacheFolder, name, $"{cacheFileType}-{LatestVersionTag}.json");
string latestLibraryVersionCacheFile = Path.Combine(_cacheFolder, name, $"{cacheFileType}-{ManifestConstants.LatestVersion}.json");

string latestVersionContent = await _cacheService.GetContentsFromUriWithCacheFallbackAsync(latestLibraryVersionUrl,
latestLibraryVersionCacheFile,
Expand Down Expand Up @@ -116,7 +115,7 @@ public async Task<ILibrary> GetLibraryAsync(string name, string version, Cancell
}

string libraryId = _libraryNamingScheme.GetLibraryId(name, version);
if (string.Equals(version, LatestVersionTag, StringComparison.Ordinal))
if (string.Equals(version, ManifestConstants.LatestVersion, StringComparison.Ordinal))
{
string latestVersion = await GetLatestVersion(libraryId, includePreReleases: false, cancellationToken).ConfigureAwait(false);
libraryId = _libraryNamingScheme.GetLibraryId(name, latestVersion);
Expand Down Expand Up @@ -288,8 +287,8 @@ public async Task<CompletionSet> GetLibraryCompletionSetAsync(string libraryName
// support @latest version
completions.Add(new CompletionItem
{
DisplayText = LatestVersionTag,
InsertionText = _libraryNamingScheme.GetLibraryId(name, LatestVersionTag),
DisplayText = ManifestConstants.LatestVersion,
InsertionText = _libraryNamingScheme.GetLibraryId(name, ManifestConstants.LatestVersion),
});

completionSet.CompletionType = CompletionSortOrder.Version;
Expand Down
13 changes: 13 additions & 0 deletions test/LibraryManager.Test/Providers/Cdnjs/CdnjsCatalogTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,19 @@ public async Task GetLibraryAsync_Success()
Assert.IsNotNull(library.Files);
}

[TestMethod]
public async Task GetLibraryAsync_LatestVersion_Success()
{
CdnjsCatalog sut = SetupCatalog();

ILibrary library = await sut.GetLibraryAsync("sampleLibrary", "latest", CancellationToken.None);

Assert.IsNotNull(library);
Assert.AreEqual("sampleLibrary", library.Name);
Assert.AreEqual("3.1.4", library.Version);
Assert.IsNotNull(library.Files);
}

[TestMethod]
public async Task GetLibraryAsync_InvalidLibraryId()
{
Expand Down