From 5f1dca3d6150fb358088dd25585ef65acc904415 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 20 Oct 2024 19:47:49 +0100 Subject: [PATCH] dotnet package resolution --- .vscode/tasks.json | 2 +- src/Directory.Build.props | 11 + src/isn.abst/ApiConfig.cs | 2 +- src/isn.abst/isn.abst.csproj | 8 +- src/isn/isn.csproj | 5 +- .../Packages/PackagesController.Catalog.cs | 5 +- .../Packages/PackagesController.GetPackage.cs | 14 +- .../PackagesController.GetVersions.cs | 21 +- src/isnd/Data/Catalog/PackageDetails.cs | 8 +- src/isnd/Data/Packages/Dependency.cs | 5 +- src/isnd/Data/Packages/Package.cs | 6 +- src/isnd/Data/Packages/PackageVersion.cs | 6 + .../20241020181446_Authors.Designer.cs | 545 ++++++++++++++++++ src/isnd/Migrations/20241020181446_Authors.cs | 80 +++ .../ApplicationDbContextModelSnapshot.cs | 16 +- src/isnd/Services/PackageManager.cs | 95 +-- src/isnd/ViewModels/PackageSearchResult.cs | 12 +- test/data/test-isn/test-isn.csproj | 6 +- test/isnd.tests/UnitTestWebHost.cs | 14 +- 19 files changed, 777 insertions(+), 84 deletions(-) create mode 100644 src/Directory.Build.props create mode 100644 src/isnd/Migrations/20241020181446_Authors.Designer.cs create mode 100644 src/isnd/Migrations/20241020181446_Authors.cs diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 61c42ba..c8087f9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -84,7 +84,7 @@ } }, "problemMatcher": "$msCompile", - "group": "test" + "group": "none" } ] } \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..45649de --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,11 @@ + + + 1.0.8 + paul + WFPL + + + +git + + diff --git a/src/isn.abst/ApiConfig.cs b/src/isn.abst/ApiConfig.cs index 5518cc3..7c943df 100644 --- a/src/isn.abst/ApiConfig.cs +++ b/src/isn.abst/ApiConfig.cs @@ -13,7 +13,7 @@ namespace isnd.Entities public const string Registration = "/registration"; public const string Nuspec = "/nuspec"; - public const string Content = "/content"; + public const string ContentBase = "/content"; public const string Nuget = "/nuget"; public const string PackageDetailUriTemplate = Package+"/{id}/{version}"; diff --git a/src/isn.abst/isn.abst.csproj b/src/isn.abst/isn.abst.csproj index 07912d2..35776a9 100644 --- a/src/isn.abst/isn.abst.csproj +++ b/src/isn.abst/isn.abst.csproj @@ -1,13 +1,7 @@  - 1.0.1 - 1.0.7 net7.0;net8.0 - NETSDK1138 - 1.0.7.0 - 1.0.7.0 - 1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327 - + diff --git a/src/isn/isn.csproj b/src/isn/isn.csproj index 0f0a9a8..be8fa76 100644 --- a/src/isn/isn.csproj +++ b/src/isn/isn.csproj @@ -4,14 +4,11 @@ net8.0 nuget_cli 45b74c62-05bc-4603-95b4-3e80ae2fdf50 - 1.0.7 - 1.0.1 + true WTFPL true NETSDK1138 - 1.0.7.0 - 1.0.7.0 1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327 diff --git a/src/isnd/Controllers/Packages/PackagesController.Catalog.cs b/src/isnd/Controllers/Packages/PackagesController.Catalog.cs index 3284692..0c663f4 100644 --- a/src/isnd/Controllers/Packages/PackagesController.Catalog.cs +++ b/src/isnd/Controllers/Packages/PackagesController.Catalog.cs @@ -16,8 +16,9 @@ namespace isnd.Controllers } - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{version}.json")] - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")] + + + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Registration + "/{id}/{version}.json")] public async Task CatalogRegistration(string id, string version) { if ("index" == version) diff --git a/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs b/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs index 40113df..5cffd8f 100644 --- a/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs +++ b/src/isnd/Controllers/Packages/PackagesController.GetPackage.cs @@ -9,18 +9,16 @@ namespace isnd.Controllers { public partial class PackagesController { - // Web get the paquet - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuget + "/{id}/{lower}/{idf}-{lowerFromName}." - + Constants.PacketFileExtension)] - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Content + "/{id}/{lower}/{idf}-{lowerFromName}." + + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.ContentBase + "/{id}/{version}/{idf}.{versionFromName}." + Constants.PacketFileExtension)] public IActionResult GetPackage( [FromRoute][SafeName][Required] string id, - [FromRoute][SafeName][Required] string lower, - [FromRoute] string idf, [FromRoute] string lowerFromName) + [FromRoute][SafeName][Required] string version, + [FromRoute] string idf, [FromRoute] string versionFromName) { var pkgPath = Path.Combine(isndSettings.PackagesRootDir, - id, lower, $"{id}-{lower}." + Constants.PacketFileExtension + id, version, $"{id}-{version}." + Constants.PacketFileExtension ); FileInfo pkgFileInfo = new FileInfo(pkgPath); @@ -33,7 +31,7 @@ namespace isnd.Controllers } // Web get spec - [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.Nuspec + "/{id}/{lower}/{idf}-{lowerFromName}." + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.ContentBase + "/{id}/{lower}/{idf}-{lowerFromName}." + Constants.SpecFileExtension)] public IActionResult GetNuspec( [FromRoute][SafeName][Required] string id, diff --git a/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs b/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs index 90550cd..f766b50 100644 --- a/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs +++ b/src/isnd/Controllers/Packages/PackagesController.GetVersions.cs @@ -1,28 +1,37 @@ using Microsoft.AspNetCore.Mvc; using NuGet.Versioning; using isnd.Entities; +using isn.abst; namespace isnd.Controllers { public partial class PackagesController { - [HttpGet("~" + ApiConfig.V2Find)] + [HttpGet("~" + Constants.ApiVersionPrefix + ApiConfig.ContentBase + "/{id}/{version}.json")] + public IActionResult GetVersions( string id, - string lower, + string version, bool prerelease = false, string packageType = null, int skip = 0, - int take = 25) + int take = 50) { + NuGetVersion parsedVersion=null; if (take > maxTake) { ModelState.AddModelError("take", "Maximum exceeded"); } - // NugetVersion - if (!NuGetVersion.TryParse(lower, out NuGetVersion parsedVersion)) + if ("index"==version) { - ModelState.AddModelError("lower", "invalid version string"); + version=null; + } + if (version!=null) + { + if (!NuGetVersion.TryParse(version, out parsedVersion)) + { + ModelState.AddModelError("version", "invalid version string"); + } } if (!ModelState.IsValid) { diff --git a/src/isnd/Data/Catalog/PackageDetails.cs b/src/isnd/Data/Catalog/PackageDetails.cs index c831014..8dba848 100644 --- a/src/isnd/Data/Catalog/PackageDetails.cs +++ b/src/isnd/Data/Catalog/PackageDetails.cs @@ -37,6 +37,9 @@ namespace isnd.Data.Catalog { DependencySets = pkg.DependencyGroups; } + Description = pkg.Description; + Owners = pkg.Package.Owner.Email; + // TODO Licence Project Urls, Summary, Title, Owners, etc ... } @@ -127,11 +130,8 @@ namespace isnd.Data.Catalog [JsonProperty("id")] public string PackageId { get; set; } - public long? DownloadCount { get; set; } - public PackageIdentity Identity{ get; set; } - public Uri ReadmeUrl { get; set; } public Uri ReportAbuseUrl { get; set; } @@ -140,8 +140,6 @@ namespace isnd.Data.Catalog public bool Listed { get; set; } - public bool PrefixReserved { get; set; } - public LicenseMetadata LicenseMetadata { get; set; } diff --git a/src/isnd/Data/Packages/Dependency.cs b/src/isnd/Data/Packages/Dependency.cs index cbc7328..5183475 100644 --- a/src/isnd/Data/Packages/Dependency.cs +++ b/src/isnd/Data/Packages/Dependency.cs @@ -32,8 +32,11 @@ namespace isnd.Data public virtual PackageDependencyGroup Group{ get; set; } // TODO Version Range - [JsonProperty("range")] + [JsonProperty("range")][StringLength(1024)] public string Version { get; set; } + [JsonProperty("exclude")][StringLength(2048)] + public string Exclude { get; set; } + } } \ No newline at end of file diff --git a/src/isnd/Data/Packages/Package.cs b/src/isnd/Data/Packages/Package.cs index ece5613..8035c3c 100644 --- a/src/isnd/Data/Packages/Package.cs +++ b/src/isnd/Data/Packages/Package.cs @@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using isnd.Interfaces; using Newtonsoft.Json; +using NuGet.Versioning; namespace isnd.Data.Packages { @@ -48,9 +49,10 @@ namespace isnd.Data.Packages public virtual Commit LatestCommit { get; set; } - internal string GetLatestVersion() + public PackageVersion GetLatestVersion() { - return Versions.Max(v => v.NugetVersion)?.ToFullString(); + var latest = Versions.Max(v => v.NugetVersion); + return Versions.First(v=> v.NugetVersion == latest); } } } \ No newline at end of file diff --git a/src/isnd/Data/Packages/PackageVersion.cs b/src/isnd/Data/Packages/PackageVersion.cs index c73d7af..7f84f4d 100644 --- a/src/isnd/Data/Packages/PackageVersion.cs +++ b/src/isnd/Data/Packages/PackageVersion.cs @@ -80,5 +80,11 @@ namespace isnd.Data } public bool IsDeleted => LatestCommit?.Action == PackageAction.DeletePackage; + + [StringLength(1024)] + public string Authors { get; set; } + + [StringLength(1024)] + public string Description { get; set; } } } \ No newline at end of file diff --git a/src/isnd/Migrations/20241020181446_Authors.Designer.cs b/src/isnd/Migrations/20241020181446_Authors.Designer.cs new file mode 100644 index 0000000..887dc58 --- /dev/null +++ b/src/isnd/Migrations/20241020181446_Authors.Designer.cs @@ -0,0 +1,545 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using isnd.Data; + +#nullable disable + +namespace isnd.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20241020181446_Authors")] + partial class Authors + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ValidityPeriodInDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("isnd.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FullName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("isnd.Data.Dependency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("DependencyGroupId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Exclude") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("PackageId") + .HasColumnType("text"); + + b.Property("Version") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("Id"); + + b.HasIndex("DependencyGroupId"); + + b.ToTable("Dependencies"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("PackageId") + .IsRequired() + .HasColumnType("character varying(1024)"); + + b.Property("PackageVersionFullString") + .IsRequired() + .HasColumnType("character varying(256)"); + + b.Property("TargetFramework") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PackageId", "PackageVersionFullString"); + + b.ToTable("PackageDependencyGroups"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.Property("PackageId") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("FullString") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Authors") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("CommitNId") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("IsPrerelease") + .HasColumnType("boolean"); + + b.Property("Major") + .HasColumnType("integer"); + + b.Property("Minor") + .HasColumnType("integer"); + + b.Property("Patch") + .HasColumnType("integer"); + + b.Property("Revision") + .HasColumnType("integer"); + + b.Property("Type") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("PackageId", "FullString"); + + b.HasIndex("CommitNId"); + + b.ToTable("PackageVersions"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Commit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer"); + + b.Property("TimeStamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Commits"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Package", b => + { + b.Property("Id") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("CommitNId") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Public") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("CommitNId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Packages"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("isnd.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("isnd.Data.ApiKeys.ApiKey", b => + { + b.HasOne("isnd.Data.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("isnd.Data.Dependency", b => + { + b.HasOne("isnd.Data.PackageDependencyGroup", "Group") + .WithMany("Dependencies") + .HasForeignKey("DependencyGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.HasOne("isnd.Data.PackageVersion", "PackageVersion") + .WithMany("DependencyGroups") + .HasForeignKey("PackageId", "PackageVersionFullString") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PackageVersion"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.HasOne("isnd.Data.Packages.Commit", "LatestCommit") + .WithMany("Versions") + .HasForeignKey("CommitNId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("isnd.Data.Packages.Package", "Package") + .WithMany("Versions") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LatestCommit"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Package", b => + { + b.HasOne("isnd.Data.Packages.Commit", "LatestCommit") + .WithMany() + .HasForeignKey("CommitNId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("isnd.Data.ApplicationUser", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LatestCommit"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("isnd.Data.PackageDependencyGroup", b => + { + b.Navigation("Dependencies"); + }); + + modelBuilder.Entity("isnd.Data.PackageVersion", b => + { + b.Navigation("DependencyGroups"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Commit", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("isnd.Data.Packages.Package", b => + { + b.Navigation("Versions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/isnd/Migrations/20241020181446_Authors.cs b/src/isnd/Migrations/20241020181446_Authors.cs new file mode 100644 index 0000000..1cdecc4 --- /dev/null +++ b/src/isnd/Migrations/20241020181446_Authors.cs @@ -0,0 +1,80 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace isnd.Migrations +{ + /// + public partial class Authors : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Authors", + table: "PackageVersions", + type: "character varying(1024)", + maxLength: 1024, + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "PackageVersions", + type: "character varying(1024)", + maxLength: 1024, + nullable: true); + + migrationBuilder.AlterColumn( + name: "Version", + table: "Dependencies", + type: "character varying(1024)", + maxLength: 1024, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Exclude", + table: "Dependencies", + type: "character varying(2048)", + maxLength: 2048, + nullable: true, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Authors", + table: "PackageVersions"); + + migrationBuilder.DropColumn( + name: "Description", + table: "PackageVersions"); + + migrationBuilder.AlterColumn( + name: "Version", + table: "Dependencies", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(1024)", + oldMaxLength: 1024, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Exclude", + table: "Dependencies", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(2048)", + oldMaxLength: 2048, + oldNullable: true); + } + } +} diff --git a/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs b/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs index c53c54a..64c2c58 100644 --- a/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/isnd/Migrations/ApplicationDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace isnd.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("ProductVersion", "8.0.10") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -258,13 +258,15 @@ namespace isnd.Migrations .HasColumnType("text"); b.Property("Exclude") - .HasColumnType("text"); + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); b.Property("PackageId") .HasColumnType("text"); b.Property("Version") - .HasColumnType("text"); + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); b.HasKey("Id"); @@ -308,9 +310,17 @@ namespace isnd.Migrations .HasMaxLength(256) .HasColumnType("character varying(256)"); + b.Property("Authors") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + b.Property("CommitNId") .HasColumnType("bigint"); + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + b.Property("IsPrerelease") .HasColumnType("boolean"); diff --git a/src/isnd/Services/PackageManager.cs b/src/isnd/Services/PackageManager.cs index 599a7c3..b731a17 100644 --- a/src/isnd/Services/PackageManager.cs +++ b/src/isnd/Services/PackageManager.cs @@ -19,6 +19,7 @@ using NuGet.Versioning; using System.Xml; using System.Xml.Linq; using NuGet.Protocol; +using System.ComponentModel; namespace isnd.Services { @@ -53,7 +54,7 @@ namespace isnd.Services Comment = "URI template used by NuGet Client to construct details URL for packages" }, - new Resource(apiBase + ApiConfig.Content, + new Resource(apiBase + ApiConfig.ContentBase + "/", "PackageBaseAddress/3.0.0") { Comment = "Package Base Address service - " + @@ -124,16 +125,39 @@ namespace isnd.Services int skip = 0, int take = 25) { - return dbContext.PackageVersions.Where( - v => v.PackageId == id - && (prerelease || !v.IsPrerelease) - && (packageType == null || v.Type == packageType) - && (parsedVersion == null || parsedVersion.CompareTo - (new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0) - ) - .OrderBy(v => v.NugetVersion) - .Select(v => v.FullString) - .Skip(skip).Take(take).ToArray(); + IQueryable results = + (parsedVersion != null)? + (packageType == null) ? + dbContext.PackageVersions.Where( + v => v.PackageId == id + && (prerelease || !v.IsPrerelease) + && (parsedVersion.CompareTo(new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0) + ) + : + dbContext.PackageVersions.Where( + v => v.PackageId == id + && (prerelease || !v.IsPrerelease) + && (v.Type == packageType) + && (parsedVersion.CompareTo(new SemanticVersion(v.Major, v.Minor, v.Patch)) < 0) + ) + + : + (packageType == null) ? + dbContext.PackageVersions.Where( + v => v.PackageId == id + && (prerelease || !v.IsPrerelease) + ) + : + dbContext.PackageVersions.Where( + v => v.PackageId == id + && (prerelease || !v.IsPrerelease) + && (v.Type == packageType) + ) + ; + + return [.. results + .Select(v => v.FullString) + .Skip(skip).Take(take)]; } public string CatalogBaseUrl => apiBase; @@ -218,16 +242,16 @@ namespace isnd.Services (string pkgId, string version, string type) { var pkg = await dbContext.PackageVersions - .Include(v=>v.Package) - .Include(v=>v.Package.Owner) - .Include(v=>v.LatestCommit) - .Include(v=>v.DependencyGroups) + .Include(v => v.Package) + .Include(v => v.Package.Owner) + .Include(v => v.LatestCommit) + .Include(v => v.DependencyGroups) .SingleOrDefaultAsync( v => v.PackageId == pkgId && v.FullString == version && - (type==null || v.Type == type)) + (type == null || v.Type == type)) ; - if (pkg == null) return null; + if (pkg == null) return null; foreach (var g in pkg.DependencyGroups) { g.Dependencies = dbContext.Dependencies.Where(d => d.DependencyGroupId == g.Id).ToList(); @@ -249,7 +273,7 @@ namespace isnd.Services && v.LatestCommit != null && (pkgType == null || pkgType == v.Type) ).SingleOrDefaultAsync(); - if (version==null) return null; + if (version == null) return null; foreach (var g in version.DependencyGroups) { g.Dependencies = dbContext.Dependencies.Where(d => d.DependencyGroupId == g.Id).ToList(); @@ -263,7 +287,7 @@ namespace isnd.Services PackageVersion packageVersion = await dbContext.PackageVersions .Include(pv => pv.Package) .FirstOrDefaultAsync(m => m.PackageId == id - && m.FullString == lower && (type==null || m.Type == type)); + && m.FullString == lower && (type == null || m.Type == type)); if (packageVersion == null) return null; if (packageVersion.Package.OwnerId != uid) return null; return new PackageDeletionReport { Deleted = true, DeletedVersion = packageVersion }; @@ -327,10 +351,10 @@ namespace isnd.Services query.Query = ""; var packages = await dbContext.Packages - .Include(g => g.Versions).OrderBy(v=>v.CommitNId) - .Where(d => d.Id.StartsWith(query.Query) + .Include(g => g.Versions).OrderBy(v => v.CommitNId) + .Where(d => d.Id.StartsWith(query.Query) && (query.Prerelease || d.Versions.Any(v => !v.IsPrerelease))) - .Where(p=>p.Versions.Count>=0) + .Where(p => p.Versions.Count >= 0) .Skip(query.Skip).Take(query.Take).ToArrayAsync(); foreach (var package in packages) foreach (var version in package.Versions) @@ -363,11 +387,13 @@ namespace isnd.Services var xMeta = XElement.Load(xmlReader, LoadOptions.None).Descendants().First(); - string packageDescription = xMeta.Descendants().FirstOrDefault(x => x.Name.LocalName == "description")?.Value; + var xMetaElts = xMeta.Descendants(); + + string description = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "description")?.Value; var dependencies = xMeta .Descendants().FirstOrDefault(x => x.Name.LocalName == "dependencies"); - var frameworkReferences= xMeta + var frameworkReferences = xMeta .Descendants().FirstOrDefault(x => x.Name.LocalName == "frameworkReferences"); var frameWorks = (dependencies ?? frameworkReferences) @@ -375,8 +401,8 @@ namespace isnd.Services .Select(x => NewFrameworkDependencyGroup(x)).ToArray(); // FIXME default package type or null var types = "Dependency"; - pkgId = xMeta.Descendants().FirstOrDefault(x => x.Name.LocalName == "id")?.Value; - string pkgVersion = xMeta.Descendants().FirstOrDefault(x => x.Name.LocalName == "version")?.Value; + pkgId = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "id")?.Value; + string pkgVersion = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "version")?.Value; if (!NuGetVersion.TryParse(pkgVersion, out nugetVersion)) throw new InvalidPackageException("metadata/version"); @@ -387,6 +413,8 @@ namespace isnd.Services string name = $"{pkgId}-{nugetVersion}." + Constants.PacketFileExtension; fullPath = Path.Combine(pkgPath, name); + var authors = xMetaElts.FirstOrDefault(x => x.Name.LocalName == "authors")?.Value; + var packageIdPathInfo = new DirectoryInfo(packageIdPath); Data.Packages.Package pkg = dbContext.Packages.SingleOrDefault(p => p.Id == pkgId); Commit commit = new Commit @@ -405,12 +433,11 @@ namespace isnd.Services { Id = pkgId, OwnerId = ownerId, + Public = true, }; dbContext.Packages.Add(pkg); } - pkg.Public = true; pkg.LatestCommit = commit; - pkg.Description = packageDescription; // here, the package is or new, or owned by the key owner if (!packageIdPathInfo.Exists) packageIdPathInfo.Create(); @@ -447,7 +474,9 @@ namespace isnd.Services IsPrerelease = nugetVersion.IsPrerelease, FullString = versionFullString, Type = types, - LatestCommit = commit + LatestCommit = commit, + Authors = authors, + Description = description }); dbContext.Commits.Add(commit); @@ -514,10 +543,10 @@ namespace isnd.Services var frameworkReferences = x.Descendants(); var framework = x.Attribute("targetFramework").Value; var deps = frameworkReferences.Select(r => new ShortDependencyInfo - { - PackageId = (r.Attribute("name") ?? r.Attribute("id")).Value, - PackageVersion = r.Attribute("version")?.Value - }); + { + PackageId = (r.Attribute("name") ?? r.Attribute("id")).Value, + PackageVersion = r.Attribute("version")?.Value + }); return new FrameworkDependencyGroup { diff --git a/src/isnd/ViewModels/PackageSearchResult.cs b/src/isnd/ViewModels/PackageSearchResult.cs index a930f63..04c27d0 100644 --- a/src/isnd/ViewModels/PackageSearchResult.cs +++ b/src/isnd/ViewModels/PackageSearchResult.cs @@ -34,18 +34,20 @@ namespace isnd.ViewModels private static PackageHit NewPackageHit(string apiBase, Package package) { string regId = $"{apiBase}{ApiConfig.Registration}/{package.Id}/index.json"; - + var latest = package.GetLatestVersion(); + if (latest==null) return null; + var pkgHit = new PackageHit(regId, package.Id) { - version = package.GetLatestVersion(), - description = package.Description, + version = latest.NugetVersion.ToString(), + description = latest.Description, }; if (package.Versions!=null) { pkgHit.versions = package.Versions .Select(v => new SearchVersionInfo(apiBase, v)).ToArray(); - pkgHit.packageTypes = package.Versions - .Select(v=>new PackageType(v.Type ?? "Legacy", new System.Version(v.Major,v.Minor,v.Patch, v.Revision)))?.ToArray(); + pkgHit.packageTypes = package.Versions.Where(v=> v.Type!=null) + .Select(v=>new PackageType(v.Type, new System.Version(v.Major,v.Minor,v.Patch, v.Revision)))?.ToArray(); } return pkgHit; } diff --git a/test/data/test-isn/test-isn.csproj b/test/data/test-isn/test-isn.csproj index 0247e7a..e1b387e 100644 --- a/test/data/test-isn/test-isn.csproj +++ b/test/data/test-isn/test-isn.csproj @@ -1,7 +1,7 @@  Exe - net7.0 + net8.0 test_isn enable enable @@ -9,7 +9,11 @@ 1.0.7.0 1.0.7+Branch.main.Sha.3695c1742965d93eba0ad851656cfaa3e44ba327 1.0.7 + + + + diff --git a/test/isnd.tests/UnitTestWebHost.cs b/test/isnd.tests/UnitTestWebHost.cs index 6a9fe71..a6c61e4 100644 --- a/test/isnd.tests/UnitTestWebHost.cs +++ b/test/isnd.tests/UnitTestWebHost.cs @@ -94,7 +94,7 @@ namespace isnd.host.tests } [Fact] - public void TrueTestRegistrationV3Resource() + public async Task TrueTestRegistrationV3Resource() { using (var serviceScope = server.Host.Services.CreateScope()) { @@ -103,7 +103,10 @@ namespace isnd.host.tests var prov = new RegistrationResourceV3Provider(); var source = new PackageSource(pkgSourceUrl); var repo = new SourceRepository(source, new INuGetResourceProvider[] { prov }); - prov.TryCreate(repo, CancellationToken.None); + (bool ok, INuGetResource res) = await prov.TryCreate(repo, CancellationToken.None); + + // FIXME FALSE Assert.True(ok); + // FIXME FALSE Assert.NotNull(res); } } @@ -167,7 +170,8 @@ namespace isnd.host.tests { Console.WriteLine($"Found package {result.Identity.Id} {result.Identity.Version}"); } - Assert.NotEmpty( meta.Where(result => result.DependencySets.Any())); + + Assert.True( meta.Where(result => result.DependencySets.Any()).Count()>0); } [Fact] @@ -179,13 +183,13 @@ namespace isnd.host.tests PackageUpdateResource pushRes = await repository.GetResourceAsync(); SymbolPackageUpdateResourceV3 symbolPackageResource = await repository.GetResourceAsync(); - await pushRes.Push(new List{ "../../../../../src/isn.abst/bin/Release/isn.abst.1.0.24.nupkg" }, null, + await pushRes.Push(new List{ "../../../../../src/isn.abst/bin/Release/isn.abst.1.0.1.nupkg" }, null, 5000, false, GetApiKey, GetSymbolsApiKey, false, false, symbolPackageResource, logger); } // not yet from testing url a [Fact] - public async Task TestGetPackageUri() + public async Task TestShouldGetPackageUri() { PackageSource source = new PackageSource("https://isn.pschneider.fr/v3/index.json"); source.ProtocolVersion=3;