Skip to content

Commit

Permalink
Add support for webapp publishing
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Mar 13, 2022
1 parent f33586e commit 9d6faa6
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 23 deletions.
4 changes: 4 additions & 0 deletions src/dotnet-releaser/Configuration/ReleaserConfiguration.cs
Expand Up @@ -23,6 +23,7 @@ public ReleaserConfiguration()
Test = new TestConfiguration();
MSBuild = new MSBuildConfiguration();
Changelog = new ChangelogConfiguration();
WebApp = new WebAppConfiguration();
GitHub = new GitHubDevHostingConfiguration();
NuGet = new NuGetPublisher();
Brew = new BrewPublisher();
Expand All @@ -48,6 +49,9 @@ public ReleaserConfiguration()

public MSBuildConfiguration MSBuild { get; }

[DataMember(Name = "webapp")]
public WebAppConfiguration WebApp { get; }

[DataMember(Name="github")]
public GitHubDevHostingConfiguration GitHub { get; }

Expand Down
8 changes: 8 additions & 0 deletions src/dotnet-releaser/Configuration/WebAppConfiguration.cs
@@ -0,0 +1,8 @@
namespace DotNetReleaser.Configuration;

public class WebAppConfiguration : ConfigurationBase
{
public WebAppConfiguration()
{
}
}
9 changes: 8 additions & 1 deletion src/dotnet-releaser/ProjectPackageInfo.cs
@@ -1,5 +1,12 @@
using System.Collections.Generic;
using System.IO;

namespace DotNetReleaser;

public record ProjectPackageInfo(string ProjectFullPath, string Name, string AssemblyName, PackageOutputType OutputType, string Version, string Description, string License, string ProjectUrl, bool IsPackable, bool IsTestProject, string[] ProjectReferences, TargetFrameworkInfo TargetFrameworkInfo);
public record ProjectPackageInfo(string ProjectFullPath, string PackageId, string AssemblyName, PackageOutputType OutputType, string Version, string Description, string License, string ProjectUrl, bool IsPackable, bool IsTestProject,
string[] ProjectReferences, TargetFrameworkInfo TargetFrameworkInfo, bool IsWebApp)
{
public string ProjectName => Path.GetFileNameWithoutExtension(ProjectFullPath);

public string? WebAppPublishProfile { get; set; }
}
4 changes: 2 additions & 2 deletions src/dotnet-releaser/ReleaserApp.AppPackaging.cs
Expand Up @@ -42,7 +42,7 @@ private async Task<List<AppPackageInfo>> BuildAppPackages(BuildInformation build
return entriesToPublish;
}

_logger.LogStartGroup($"App Packaging {packageInfo.Name} - {packageInfo.Version}");
_logger.LogStartGroup($"App Packaging {packageInfo.PackageId} - {packageInfo.Version}");

var table = new Table();
table.AddColumn("Platform");
Expand Down Expand Up @@ -84,7 +84,7 @@ private async Task<List<AppPackageInfo>> BuildAppPackages(BuildInformation build
exitPackOnError:
if (HasErrors)
{
Error($"Error while building platform packages for `{packageInfo.Name}`.");
Error($"Error while building platform packages for `{packageInfo.PackageId}`.");
}
}
}
Expand Down
40 changes: 37 additions & 3 deletions src/dotnet-releaser/ReleaserApp.Configuring.cs
Expand Up @@ -15,7 +15,7 @@ namespace DotNetReleaser;

public partial class ReleaserApp
{
private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting, IDevHosting? devHostingExtra)?> Configuring(string configurationFile, BuildKind buildKind, string githubApiToken, string? githubApiTokenExtra, string? nugetApiToken, bool forceArtifactsFolder)
private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting, IDevHosting? devHostingExtra)?> Configuring(string configurationFile, BuildKind buildKind, string githubApiToken, string? githubApiTokenExtra, string? nugetApiToken, bool forceArtifactsFolder, IReadOnlyList<string> webAppProfiles)
{
// ------------------------------------------------------------------
// Load Configuration
Expand All @@ -36,7 +36,10 @@ private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting,
// ------------------------------------------------------------------
var buildInformation = await LoadProjects();
if (buildInformation is null || HasErrors) return null; // return false;


// Find and assign PublishProfile for WebApp publishing
AssignWebAppProfiles(buildInformation, webAppProfiles);

// ------------------------------------------------------------------
// Validate Publish parameters
// ------------------------------------------------------------------
Expand Down Expand Up @@ -133,7 +136,7 @@ private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting,
buildInformation.AllowPublishDraft = true;
}

if (_config.NuGet.Publish && string.IsNullOrEmpty(nugetApiToken))
if (_config.NuGet.Publish && string.IsNullOrEmpty(nugetApiToken) && buildInformation.GetAllPackableProjects().Count > 0)
{
Error("Publishing to NuGet requires to pass --nuget-token");
return null; // return false;
Expand Down Expand Up @@ -166,4 +169,35 @@ private async Task<(BuildInformation? buildInformation, IDevHosting? devHosting,

return (buildInformation, devHosting, devHostingExtra);
}

private void AssignWebAppProfiles(BuildInformation buildInformation, IReadOnlyList<string> webAppProfiles)
{
for (var i = 0; i < webAppProfiles.Count; i++)
{
var webAppProfile = webAppProfiles[i];
var indexOfEqual = webAppProfile.IndexOf('=');
if (indexOfEqual < 0)
{
Error($"Invalid publish profile at {i}. Expecting an equal `=` between <ProjectName>=<PublishProfile>.");
continue;
}

var projectName = webAppProfile.Substring(0, indexOfEqual).Trim();
var publishProfile = webAppProfile.Substring(indexOfEqual + 1).Trim();
if (publishProfile == "")
{
Error($"Invalid empty publish profile at {i}. Expecting a publish profile after the ProjectName: <ProjectName>=<PublishProfile>.");
continue;
}

var projectPackageInfo = buildInformation.ProjectPackageInfoCollections.SelectMany(x => x.Packages).FirstOrDefault(x => x.ProjectName == projectName);
if (projectPackageInfo is null)
{
Error($"Invalid publish profile at {i}. The ProjectName `{projectName}` was not found in the MSBuild project name list [{string.Join(", ", buildInformation.ProjectPackageInfoCollections.SelectMany(x => x.Packages).Select(x => x.ProjectName))}]");
continue;
}

projectPackageInfo.WebAppPublishProfile = publishProfile;
}
}
}
7 changes: 4 additions & 3 deletions src/dotnet-releaser/ReleaserApp.NuGet.cs
Expand Up @@ -11,12 +11,13 @@ public partial class ReleaserApp
{
private async Task<bool> BuildNuGetPackage(BuildInformation buildInfo)
{
if (!_config.NuGet.Publish) return true;
var packableProjects = buildInfo.GetAllPackableProjects();
if (!_config.NuGet.Publish || packableProjects.Count == 0) return true;

try
{
_logger.LogStartGroup($"NuGet Packaging - {buildInfo.Version}");
foreach (var projectPackageInfo in buildInfo.GetAllPackableProjects())
foreach (var projectPackageInfo in packableProjects)
{
var nugetPackages = await BuildNuGetPackageImpl(projectPackageInfo);
if (nugetPackages is null)
Expand Down Expand Up @@ -45,7 +46,7 @@ private async Task<bool> BuildNuGetPackage(BuildInformation buildInfo)

private async Task<List<string>?> BuildNuGetPackageImpl(ProjectPackageInfo projectPackageInfo)
{
Info($"Building NuGet Package - {projectPackageInfo.Name}");
Info($"Building NuGet Package - {projectPackageInfo.PackageId}");
var restoreResult = await RunMSBuild(projectPackageInfo.ProjectFullPath, "Restore");
if (restoreResult is null)
{
Expand Down
38 changes: 31 additions & 7 deletions src/dotnet-releaser/ReleaserApp.Projects.cs
Expand Up @@ -62,6 +62,11 @@ public List<ProjectPackageInfo> GetAllPackableProjects()
{
return ProjectPackageInfoCollections.SelectMany(x => x.Packages).Where(x => x.IsPackable).ToList();
}

public List<ProjectPackageInfo> GetAllWebAppProjects()
{
return ProjectPackageInfoCollections.SelectMany(x => x.Packages).Where(x => x.IsWebApp).ToList();
}
}


Expand Down Expand Up @@ -162,8 +167,9 @@ public partial class ReleaserApp
var packageVersion = outputs.First(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.PackageVersion).ItemSpec;
var packageDescription = outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.PackageDescription)?.ItemSpec;
var packageLicenseExpression = outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.PackageLicenseExpression)?.ItemSpec;
var packageOutputType = outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.PackageOutputType)?.ItemSpec?.Trim() ?? string.Empty;
var packageOutputTypeStr = outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.PackageOutputType)?.ItemSpec?.Trim() ?? string.Empty;
var packageProjectUrl = outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.PackageProjectUrl)?.ItemSpec ?? $"{_config.GitHub.GetUrl()}";
var usingSdkWeb = string.Equals(outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.UsingMicrosoftNETSdkWeb)?.ItemSpec?.Trim(), "true", StringComparison.OrdinalIgnoreCase);
var isNuGetPackable = string.Equals(outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.IsNuGetPackable)?.ItemSpec?.Trim(), "true", StringComparison.OrdinalIgnoreCase);
var isTestProject = string.Equals(outputs.FirstOrDefault(x => x.GetMetadata(ReleaserConstants.ItemSpecKind) == ReleaserConstants.IsTestProject)?.ItemSpec?.Trim(), "true", StringComparison.OrdinalIgnoreCase);

Expand All @@ -177,13 +183,15 @@ public partial class ReleaserApp
projectReferences.Add(projectReferenceFullPath);
}

if (!Enum.TryParse<PackageOutputType>(packageOutputType, true, out var result))
if (!Enum.TryParse<PackageOutputType>(packageOutputTypeStr, true, out var packageOutputType))
{
Error($"Unsupported project type `{packageOutputType}` found for project `{projectFullFilePath}`");
Error($"Unsupported project type `{packageOutputTypeStr}` found for project `{projectFullFilePath}`");
return null;
}

return new ProjectPackageInfo(projectFullFilePath, packageId, assemblyName, result, packageVersion, packageDescription ?? "No description found", packageLicenseExpression ?? "No license found", packageProjectUrl, isNuGetPackable, isTestProject, projectReferences.ToArray(), targetFrameworkInfo);
bool isWebApp = packageOutputType != PackageOutputType.Library && usingSdkWeb;

return new ProjectPackageInfo(projectFullFilePath, packageId, assemblyName, packageOutputType, packageVersion, packageDescription ?? "No description found", packageLicenseExpression ?? "No license found", packageProjectUrl, isNuGetPackable, isTestProject, projectReferences.ToArray(), targetFrameworkInfo, isWebApp);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -386,6 +394,15 @@ private string VerifyVersionsAndDisplayAllProjects(List<ProjectPackageInfoCollec
table.AddColumn("License");
table.AddColumn(new TableColumn("Packable?").Centered());
table.AddColumn(new TableColumn("Test?").Centered());


bool hasWebApps = projectPackageInfoCollections.SelectMany(x => x.Packages).Any(x => x.IsWebApp);
if (hasWebApps)
{
table.AddColumn(new TableColumn("WebApp?").Centered());
}


table.Border = _tableBorder;

var row = new List<object>();
Expand Down Expand Up @@ -424,7 +441,8 @@ private string VerifyVersionsAndDisplayAllProjects(List<ProjectPackageInfoCollec
bool invalidVersion = project.IsPackable && version != project.Version;
int c = 0;
row[c++] = project.AssemblyName;
row[c++] = project.OutputType.ToString().ToLowerInvariant();
var outputTypeStr = project.OutputType.ToString().ToLowerInvariant();
row[c++] = outputTypeStr;
row[c++] = invalidVersion ? $"{project.Version} (invalid)" : project.Version;
row[c++] = string.Join("\n", project.TargetFrameworkInfo.TargetFrameworks);
if (project.IsPackable)
Expand All @@ -439,12 +457,17 @@ private string VerifyVersionsAndDisplayAllProjects(List<ProjectPackageInfoCollec
}

row[c++] = project.IsPackable ? "x" : string.Empty;
row[c] = project.IsTestProject ? "x" : string.Empty;
row[c++] = project.IsTestProject ? "x" : string.Empty;
if (invalidVersion)
{
invalidPackageVersions.Add(project);
}

if (hasWebApps)
{
row[c++] = project.IsWebApp ? "x" : string.Empty;
}

//table.AddRow(row.Select(Markup.Escape).ToArray());
table.AddRow(row.Select(x => x is IRenderable renderable ? renderable : new Text(x.ToString() ?? string.Empty)).ToArray());
}
Expand All @@ -460,7 +483,8 @@ private string VerifyVersionsAndDisplayAllProjects(List<ProjectPackageInfoCollec
}
}

if (string.IsNullOrEmpty(version))
// Produce an error only if we have packable projects without a version
if (string.IsNullOrEmpty(version) && projectPackageInfoCollections.SelectMany(x => x.Packages).Any(x => x.IsPackable))
{
Error("No version found from all projects");
}
Expand Down
4 changes: 1 addition & 3 deletions src/dotnet-releaser/ReleaserApp.Publishing.cs
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading.Tasks;
using DotNetReleaser.Changelog;
using DotNetReleaser.Configuration;
using DotNetReleaser.Helpers;

namespace DotNetReleaser;

Expand Down
70 changes: 70 additions & 0 deletions src/dotnet-releaser/ReleaserApp.WebAppPublish.cs
@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DotNetReleaser;

public partial class ReleaserApp
{
private async Task<bool> BuildAndPublishWebApp(BuildInformation buildInformation)
{
if (!_config.WebApp.Publish || buildInformation.BuildKind != BuildKind.Publish) return true;

var webApps = buildInformation.GetAllWebAppProjects();
if (webApps.Count == 0) return true;

try
{
_logger.LogStartGroup("WebApp Publishing");

foreach (var webAppProject in buildInformation.GetAllWebAppProjects())
{
if (!await BuildAndPublishWebApp(webAppProject))
{
return false;
}
}
}
finally
{
_logger.LogEndGroup();
}

return true;
}

private async Task<bool> BuildAndPublishWebApp(ProjectPackageInfo buildPackageInfo)
{
if (buildPackageInfo.WebAppPublishProfile is null)
{
Warn($"No PublishProfile for {buildPackageInfo.ProjectName}. Skipping.");
return true;
}

Info($"Publishing {buildPackageInfo.ProjectName}");

//buildPackageInfo
var properties = new Dictionary<string, object>(_config.MSBuild.Properties);

// We need to explicitly restore the platform RID before trying to build it
var restoreResult = await RunMSBuild(buildPackageInfo.ProjectFullPath, "Restore", properties);
if (restoreResult is null)
{
// Stop on first error
return false;
}

properties["PublishProfile"] = buildPackageInfo.WebAppPublishProfile;

// Publish
var result = await RunMSBuild(buildPackageInfo.ProjectFullPath, "Publish", properties);

if (result is null)
{
// Stop on first error
return false;
}

return true;

}
}

0 comments on commit 9d6faa6

Please sign in to comment.