diff --git a/src/AccountDeleter/EmptyFeatureFlagService.cs b/src/AccountDeleter/EmptyFeatureFlagService.cs
index afb3106e24..277d2e8fdb 100644
--- a/src/AccountDeleter/EmptyFeatureFlagService.cs
+++ b/src/AccountDeleter/EmptyFeatureFlagService.cs
@@ -296,6 +296,11 @@ public bool IsDisplayUploadWarningV2Enabled(User user)
throw new NotImplementedException();
}
+ public bool IsDisplayPackageReadmeWarningEnabled(User user)
+ {
+ throw new NotImplementedException();
+ }
+
public bool IsFrameworkFilteringEnabled(User user) {
throw new NotImplementedException();
}
diff --git a/src/Bootstrap/dist/css/bootstrap-theme.css b/src/Bootstrap/dist/css/bootstrap-theme.css
index f2fd116726..f8adb32ca0 100644
--- a/src/Bootstrap/dist/css/bootstrap-theme.css
+++ b/src/Bootstrap/dist/css/bootstrap-theme.css
@@ -1598,6 +1598,9 @@ p.frameworktableinfo-text {
font-weight: bold;
margin-bottom: -1px;
}
+.page-package-details .body-tabs .nav-tabs > li.active > a.body-warning-tab {
+ background-color: #fff4ce;
+}
.page-package-details .body-tabs .nav-tabs > li > a {
border-left: 0px;
border-right: 0px;
diff --git a/src/Bootstrap/less/theme/page-display-package.less b/src/Bootstrap/less/theme/page-display-package.less
index 5deac91aea..6f6565dcd2 100644
--- a/src/Bootstrap/less/theme/page-display-package.less
+++ b/src/Bootstrap/less/theme/page-display-package.less
@@ -423,6 +423,10 @@
margin-bottom: -1px;
}
+ .nav-tabs > li.active > a.body-warning-tab > {
+ background-color: #fff4ce;
+ }
+
.nav-tabs > li > a {
border-left: 0px;
border-right: 0px;
diff --git a/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs b/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs
index 20b884a364..f9237589d0 100644
--- a/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs
+++ b/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs
@@ -135,6 +135,11 @@ public bool IsDisplayUploadWarningV2Enabled(User user)
throw new NotImplementedException();
}
+ public bool IsDisplayPackageReadmeWarningEnabled(User user)
+ {
+ throw new NotImplementedException();
+ }
+
public bool IsODataDatabaseReadOnlyEnabled()
{
throw new NotImplementedException();
diff --git a/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs b/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs
index 8ac41ceee6..80f2860d1e 100644
--- a/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs
+++ b/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs
@@ -48,6 +48,7 @@ public class FeatureFlagService : IFeatureFlagService
private const string MarkdigMdRenderingFlightName = GalleryPrefix + "MarkdigMdRendering";
private const string MarkdigMdSyntaxHighlightFlightName = GalleryPrefix + "MarkdigMdSyntaxHighlight";
private const string DisplayUploadWarningV2FlightName = GalleryPrefix + "DisplayUploadWarningV2";
+ private const string DisplayPackageReadmeWarningFlightName = GalleryPrefix + "DisplayPackageReadmeWarning";
private const string DeletePackageApiFlightName = GalleryPrefix + "DeletePackageApi";
private const string ImageAllowlistFlightName = GalleryPrefix + "ImageAllowlist";
private const string DisplayBannerFlightName = GalleryPrefix + "Banner";
@@ -348,6 +349,11 @@ public bool IsDisplayUploadWarningV2Enabled(User user)
return _client.IsEnabled(DisplayUploadWarningV2FlightName, user, defaultValue: false);
}
+ public bool IsDisplayPackageReadmeWarningEnabled(User user)
+ {
+ return _client.IsEnabled(DisplayPackageReadmeWarningFlightName, user, defaultValue: false);
+ }
+
public bool IsDeletePackageApiEnabled(User user)
{
return _client.IsEnabled(DeletePackageApiFlightName, user, defaultValue: false);
diff --git a/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs b/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs
index ca7d820305..ba5da554de 100644
--- a/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs
+++ b/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs
@@ -273,6 +273,11 @@ public interface IFeatureFlagService
///
bool IsDisplayUploadWarningV2Enabled(User user);
+ ///
+ /// Whether the new warning of the missing readme is displayed to package authors
+ ///
+ bool IsDisplayPackageReadmeWarningEnabled(User user);
+
///
/// Whether or not the user can delete a package through the API.
///
diff --git a/src/NuGetGallery/App_Data/Files/Content/flags.json b/src/NuGetGallery/App_Data/Files/Content/flags.json
index 8abeeaada6..e2313044a1 100644
--- a/src/NuGetGallery/App_Data/Files/Content/flags.json
+++ b/src/NuGetGallery/App_Data/Files/Content/flags.json
@@ -120,6 +120,12 @@
"SiteAdmins": false,
"Accounts": [],
"Domains": []
+ },
+ "NuGetGallery.DisplayPackageReadmeWarning": {
+ "All": true,
+ "SiteAdmins": false,
+ "Accounts": [],
+ "Domains": []
}
}
}
\ No newline at end of file
diff --git a/src/NuGetGallery/Controllers/PackagesController.cs b/src/NuGetGallery/Controllers/PackagesController.cs
index 39a29f74ec..c1ac87e5c4 100644
--- a/src/NuGetGallery/Controllers/PackagesController.cs
+++ b/src/NuGetGallery/Controllers/PackagesController.cs
@@ -941,6 +941,8 @@ public virtual async Task DisplayPackage(string id, string version
packageRenames,
readme);
+ var canDisplayReadmeWarning = _featureFlagService.IsDisplayPackageReadmeWarningEnabled(currentUser) && !model.HasEmbeddedReadmeFile && model.ReadMeHtml == null;
+
model.ValidatingTooLong = _validationService.IsValidatingTooLong(package);
model.PackageValidationIssues = _validationService.GetLatestPackageValidationIssues(package);
model.SymbolsPackageValidationIssues = _validationService.GetLatestPackageValidationIssues(model.LatestSymbolsPackage);
@@ -956,6 +958,7 @@ public virtual async Task DisplayPackage(string id, string version
model.IsDisplayTargetFrameworkEnabled = _featureFlagService.IsDisplayTargetFrameworkEnabled(currentUser);
model.IsComputeTargetFrameworkEnabled = _featureFlagService.IsComputeTargetFrameworkEnabled();
model.IsMarkdigMdSyntaxHighlightEnabled = _featureFlagService.IsMarkdigMdSyntaxHighlightEnabled();
+ model.CanDisplayReadmeWarning = canDisplayReadmeWarning;
if (model.IsComputeTargetFrameworkEnabled || model.IsDisplayTargetFrameworkEnabled)
{
diff --git a/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs b/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs
index 2540018b67..02a1cc8331 100644
--- a/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs
+++ b/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs
@@ -44,6 +44,7 @@ public class DisplayPackageViewModel : ListPackageItemViewModel
public bool IsPackageDependentsEnabled { get; set; }
public bool IsRecentPackagesNoIndexEnabled { get; set; }
public bool IsMarkdigMdSyntaxHighlightEnabled { get; set; }
+ public bool CanDisplayReadmeWarning { get; set; }
public NuGetPackageGitHubInformation GitHubDependenciesInformation { get; set; }
public bool HasEmbeddedIcon { get; set; }
public bool HasEmbeddedReadmeFile { get; set; }
diff --git a/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml b/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml
index ae339925a9..beca0292f2 100644
--- a/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml
+++ b/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml
@@ -530,12 +530,19 @@
role="tab"
data-toggle="tab"
id="readme-body-tab"
- class="body-tab"
+ class="body-@(Model.CanDisplayReadmeWarning && Model.CanDisplayPrivateMetadata? "warning-" : "")tab"
aria-controls="readme-tab"
aria-expanded="@(activeBodyTab == "readme" ? "true" : "false")"
aria-selected="@(activeBodyTab == "readme" ? "true" : "false")"
tabindex="@(activeBodyTab == "readme" ? "0" : "-1")">
-
+ @if (Model.CanDisplayReadmeWarning && Model.CanDisplayPrivateMetadata)
+ {
+
+ }
+ else
+ {
+
+ }
README
@@ -670,7 +677,11 @@
}
else
{
- if (Model.CanDisplayPrivateMetadata)
+ if (Model.CanDisplayPrivateMetadata && Model.CanDisplayReadmeWarning)
+ {
+ @ViewHelpers.AlertWarning(@Your package is missing a README. Please update your package to include a README or add a README here.);
+ }
+ else if (Model.CanDisplayPrivateMetadata)
{
@ViewHelpers.AlertWarning(@The package description is shown below. Please update your package to include a README.);
}
diff --git a/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs b/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs
index 757a3d9084..fe4e219a62 100644
--- a/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs
+++ b/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs
@@ -127,6 +127,8 @@ public class FakeFeatureFlagService : IFeatureFlagService
public bool IsDisplayUploadWarningV2Enabled(User user) => throw new NotImplementedException();
+ public bool IsDisplayPackageReadmeWarningEnabled(User user) => throw new NotImplementedException();
+
public bool IsFrameworkFilteringEnabled(User user) => throw new NotImplementedException();
}
}