Added new destination type : gitea, and revamped build workflow
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
bin/**
|
**/bin
|
||||||
obj/**
|
**/obj
|
||||||
|
**/dist
|
||||||
@@ -135,21 +135,41 @@ sealed record CloudDestiantion(DestinationContext Context) : IDestination {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed record GithubDestination(DestinationContext Context, bool Verbose = false) : IDestination {
|
|
||||||
|
sealed record GitDestination(DestinationContext Context, string Source, string ApiKey, bool Verbose = false) : IDestination {
|
||||||
|
private static Result<string, ReadableError> GetApiKey(string host) {
|
||||||
|
var key = Environment.GetEnvironmentVariable($"git-{host}-packages-key");
|
||||||
|
if (key is null) return new ReadableError(string.Format("No key stored in EnvironmentVariables with name {0}", $"git-{host}-packages-key"), false);
|
||||||
|
return key.Ok();
|
||||||
|
}
|
||||||
|
public static Result<GitDestination, ReadableError> CreateForGitea(DestinationContext context, string repoOwner, bool verbose = false) {
|
||||||
|
// gitea source structure = https://gitea.example.com/api/packages/{owner}/nuget/index.json
|
||||||
|
var keyResult = GetApiKey("gitea");
|
||||||
|
if (keyResult is ReadableError error) return error;
|
||||||
|
return new GitDestination(context, $"https://gitea.example.com/api/packages/{repoOwner}/nuget/index.json", keyResult.Unwrap(), verbose).Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<GitDestination, ReadableError> CreateForGithub(DestinationContext context, string repoOwner, bool verbose = false) {
|
||||||
|
// github source structure = https://nuget.pkg.github.com/NAMESPACE/index.json
|
||||||
|
// namespace usually = repoOwner
|
||||||
|
var keyResult = GetApiKey("github");
|
||||||
|
if (keyResult is ReadableError error) return error;
|
||||||
|
return new GitDestination(context, $"https://nuget.pkg.github.com/{repoOwner}/index.json", keyResult.Unwrap(), verbose).Ok();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Result<Success, ReadableError>> WaitForCompletion(CancellationToken ct = default) {
|
public async Task<Result<Success, ReadableError>> WaitForCompletion(CancellationToken ct = default) {
|
||||||
var p = Process.Start(new ProcessStartInfo() {
|
using var p = Process.Start(new ProcessStartInfo() {
|
||||||
FileName = "dotnet",
|
FileName = "dotnet",
|
||||||
Arguments = $"nuget push \"{Context.PackageFile.FullName}\" --source github",
|
Arguments = $"nuget push \"{Context.PackageFile.FullName}\" -s {Source} -k {ApiKey}",
|
||||||
WorkingDirectory = Environment.CurrentDirectory,
|
WorkingDirectory = Environment.CurrentDirectory,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true
|
RedirectStandardError = true
|
||||||
});
|
});
|
||||||
|
|
||||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||||
StringBuilder errorLines = new();
|
StringBuilder errorLines = new();
|
||||||
p?.ErrorDataReceived += (sender, eventArgs) => {
|
p?.ErrorDataReceived += (sender, eventArgs) => {
|
||||||
cts.Cancel();
|
|
||||||
if (Verbose && eventArgs.Data != null)
|
if (Verbose && eventArgs.Data != null)
|
||||||
AnsiConsole.WriteLine(eventArgs.Data);
|
AnsiConsole.WriteLine(eventArgs.Data);
|
||||||
errorLines.Append(eventArgs.Data);
|
errorLines.Append(eventArgs.Data);
|
||||||
@@ -169,16 +189,16 @@ sealed record GithubDestination(DestinationContext Context, bool Verbose = false
|
|||||||
try {
|
try {
|
||||||
await (p?.WaitForExitAsync(cts.Token) ?? Task.CompletedTask);
|
await (p?.WaitForExitAsync(cts.Token) ?? Task.CompletedTask);
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException) {
|
catch (OperationCanceledException) {
|
||||||
p?.Kill();
|
p?.Kill();
|
||||||
|
await (p?.WaitForExitAsync(ct));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p?.ExitCode != 0) {
|
if (p?.ExitCode != 0) {
|
||||||
Context.Task.StopTask();
|
Context.Task.StopTask();
|
||||||
return new ReadableError(errorLines.ToString().EscapeMarkup() + "\n" + string.Format(Exceptions.dotnet_nuget_push_failure, p?.ExitCode ?? -1), false);
|
return new ReadableError(errorLines.ToString().EscapeMarkup() + "\n" + string.Format(Exceptions.dotnet_nuget_push_failure, p?.ExitCode ?? -1), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.Task.Increment(Context.BufferSize / 2);
|
Context.Task.Increment(Context.PackageSize / 2);
|
||||||
return Success.AsResult();
|
return Success.AsResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-224
@@ -1,224 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// <auto-generated>
|
|
||||||
// This code was generated by a tool.
|
|
||||||
//
|
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
|
||||||
// the code is regenerated.
|
|
||||||
// </auto-generated>
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace aeqw89.tools.Publish {
|
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
|
||||||
/// </summary>
|
|
||||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
|
||||||
// class via a tool like ResGen or Visual Studio.
|
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
|
||||||
// with the /str option, or rebuild your VS project.
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
|
||||||
internal class Exceptions {
|
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
|
||||||
internal Exceptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the cached ResourceManager instance used by this class.
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
|
||||||
get {
|
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
|
||||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("aeqw89.tools.Publish.Exceptions", typeof(Exceptions).Assembly);
|
|
||||||
resourceMan = temp;
|
|
||||||
}
|
|
||||||
return resourceMan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overrides the current thread's CurrentUICulture property for all
|
|
||||||
/// resource lookups using this strongly typed resource class.
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
|
||||||
get {
|
|
||||||
return resourceCulture;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
resourceCulture = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The cloud host '{0}' is not an entry on this user's config file..
|
|
||||||
/// </summary>
|
|
||||||
internal static string cloud_host_not_found {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("cloud_host_not_found", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The mode '{0}' is invalid, the valid modes are [overwrite|increment].
|
|
||||||
/// </summary>
|
|
||||||
internal static string could_not_parse_mode {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("could_not_parse_mode", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The increment target '{0}' is invalid, the valid increment targets are [patch|minor|patch].
|
|
||||||
/// </summary>
|
|
||||||
internal static string could_not_parse_target {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("could_not_parse_target", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The 'dotnet nuget push' command failed with error message '{0}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string dotnet_nuget_push_failure {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("dotnet_nuget_push_failure", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Failed to pack with exit code '{0}'; ensure that 'dotnet build' succeeds before running this program..
|
|
||||||
/// </summary>
|
|
||||||
internal static string dotnet_pack_failure {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("dotnet_pack_failure", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Could not delete temporary directory '{0}' due to error '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string failed_to_clean_up {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("failed_to_clean_up", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Failde to prepare an upload directory on the path {0} for the remote host '{1}', after being detected as a {2} host. Server error is '{3}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string failed_to_prepare_server_directory {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("failed_to_prepare_server_directory", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The flag '{0}' requires exactly '{1}' parameters. You have entered '{2}'..
|
|
||||||
/// </summary>
|
|
||||||
internal static string flag_parameter_length_incorrect {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("flag_parameter_length_incorrect", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The '{0}' flag requires that argument with index '{1}' be of type '{2}'. You have entered '{3}' which has failed to be converted..
|
|
||||||
/// </summary>
|
|
||||||
internal static string flag_parameter_type_incorrect {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("flag_parameter_type_incorrect", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The directory '{0}' contains multiple .csproj files; this tool can only process one at a time..
|
|
||||||
/// </summary>
|
|
||||||
internal static string found_multiple_csproj {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("found_multiple_csproj", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Something went wrong loading this file; {0}.
|
|
||||||
/// </summary>
|
|
||||||
internal static string generic_error {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("generic_error", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to You must specify at least one destination..
|
|
||||||
/// </summary>
|
|
||||||
internal static string missing_destinations {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("missing_destinations", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to You must specify an increment target if you specified an increment mode; allowed increment targets are [patch|minor|major].
|
|
||||||
/// </summary>
|
|
||||||
internal static string missing_increment_target {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("missing_increment_target", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to You must specify a mode; allowed modes are [overwrite|increment].
|
|
||||||
/// </summary>
|
|
||||||
internal static string missing_mode {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("missing_mode", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to No project file was found within the current directory..
|
|
||||||
/// </summary>
|
|
||||||
internal static string no_project_in_directory {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("no_project_in_directory", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The project file '{0}' is irreparable becuase it is missing a '{1}' property, and the value cannot be guessed..
|
|
||||||
/// </summary>
|
|
||||||
internal static string project_file_irreparable {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("project_file_irreparable", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Something went wrong; an attempt was made to load a non .csproj file as a project file..
|
|
||||||
/// </summary>
|
|
||||||
internal static string tried_loading_non_csproj_file {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("tried_loading_non_csproj_file", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to The version string '{0}' is in an unidentifiable format..
|
|
||||||
/// </summary>
|
|
||||||
internal static string version_string_not_formatted_correctly {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("version_string_not_formatted_correctly", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ using Renci.SshNet;
|
|||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using aeqw89.xml.ProjectFile;
|
using aeqw89.xml.ProjectFile;
|
||||||
|
|
||||||
|
|
||||||
namespace aeqw89.tools.Publish;
|
namespace aeqw89.tools.Publish;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -116,7 +115,7 @@ public static class Program {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
record ProjectResult(string PackageId, string Version);
|
record ProjectResult(string PackageId, string Version, string RepoOwner);
|
||||||
static async Task<Result<ProjectResult, ReadableError>> PrepareProject(RunContext rctx, StatusContext ctx) {
|
static async Task<Result<ProjectResult, ReadableError>> PrepareProject(RunContext rctx, StatusContext ctx) {
|
||||||
ctx.Status = "Locating project file";
|
ctx.Status = "Locating project file";
|
||||||
if (!ProjectFile.TryLoad(Environment.CurrentDirectory, out var projectFile, out var error))
|
if (!ProjectFile.TryLoad(Environment.CurrentDirectory, out var projectFile, out var error))
|
||||||
@@ -124,6 +123,7 @@ public static class Program {
|
|||||||
|
|
||||||
string packageId = projectFile.GetPackageId();
|
string packageId = projectFile.GetPackageId();
|
||||||
string version;
|
string version;
|
||||||
|
string repoOwner;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
projectFile.Backup();
|
projectFile.Backup();
|
||||||
@@ -161,8 +161,8 @@ public static class Program {
|
|||||||
ctx.Status = "Updating version";
|
ctx.Status = "Updating version";
|
||||||
version = projectFile.GetVersion();
|
version = projectFile.GetVersion();
|
||||||
version = ProjectFile.ChangeVersion(version, delta, rctx.Args.Target ?? IncrementTarget.Patch).Unwrap(rctx);
|
version = ProjectFile.ChangeVersion(version, delta, rctx.Args.Target ?? IncrementTarget.Patch).Unwrap(rctx);
|
||||||
|
|
||||||
projectFile.SetVersion(version);
|
projectFile.SetVersion(version);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
@@ -170,6 +170,8 @@ public static class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
version = projectFile.GetVersion();
|
version = projectFile.GetVersion();
|
||||||
|
repoOwner = projectFile.GetRepositoryOwner();
|
||||||
|
|
||||||
|
|
||||||
if (!rctx.Args.Flags.ContainsKey("--simulate")) {
|
if (!rctx.Args.Flags.ContainsKey("--simulate")) {
|
||||||
try {
|
try {
|
||||||
@@ -221,7 +223,7 @@ public static class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
projectFile.Save();
|
projectFile.Save();
|
||||||
return new Ok<ProjectResult>(new ProjectResult(packageId, version));
|
return new Ok<ProjectResult>(new ProjectResult(packageId, version, repoOwner));
|
||||||
}
|
}
|
||||||
|
|
||||||
static async Task<Result<Success, ReadableError>> PackProject(RunContext rctx, StatusContext ctx) {
|
static async Task<Result<Success, ReadableError>> PackProject(RunContext rctx, StatusContext ctx) {
|
||||||
@@ -242,6 +244,7 @@ public static class Program {
|
|||||||
enum DestinationType {
|
enum DestinationType {
|
||||||
Local,
|
Local,
|
||||||
Github,
|
Github,
|
||||||
|
Main,
|
||||||
Cloud
|
Cloud
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +289,10 @@ public static class Program {
|
|||||||
destType = DestinationType.Cloud;
|
destType = DestinationType.Cloud;
|
||||||
} else if (dest == "github") {
|
} else if (dest == "github") {
|
||||||
destType = DestinationType.Github;
|
destType = DestinationType.Github;
|
||||||
} else {
|
} else if (dest == "main") {
|
||||||
|
destType = DestinationType.Main;
|
||||||
|
}
|
||||||
|
else {
|
||||||
lock(rctx) {
|
lock(rctx) {
|
||||||
ShowError(string.Format(Exceptions.destination_unrecognizable, dest));
|
ShowError(string.Format(Exceptions.destination_unrecognizable, dest));
|
||||||
ShowHelp();
|
ShowHelp();
|
||||||
@@ -298,16 +304,20 @@ public static class Program {
|
|||||||
var dctx = new DestinationContext(task, ctx, reader, pkg.FileInfo, destType switch {
|
var dctx = new DestinationContext(task, ctx, reader, pkg.FileInfo, destType switch {
|
||||||
DestinationType.Cloud => dest["cloud-".Length..],
|
DestinationType.Cloud => dest["cloud-".Length..],
|
||||||
DestinationType.Github => dest["github".Length..],
|
DestinationType.Github => dest["github".Length..],
|
||||||
|
DestinationType.Main => dest["main".Length..],
|
||||||
DestinationType.Local => dest["local-".Length..]
|
DestinationType.Local => dest["local-".Length..]
|
||||||
}, BufferSize, pkg.Size());
|
}, BufferSize, pkg.Size());
|
||||||
|
|
||||||
IDestination destination = destType switch {
|
Result<IDestination, ReadableError> destinationResult = destType switch {
|
||||||
DestinationType.Local => new LocalDestination(dctx),
|
DestinationType.Local => new LocalDestination(dctx).Ok<IDestination>(),
|
||||||
DestinationType.Github => new GithubDestination(dctx, rctx.Args.Verbose),
|
DestinationType.Github => GitDestination.CreateForGithub(dctx, project.RepoOwner, rctx.Args.Verbose).UpcastSuccess<GitDestination, IDestination, ReadableError>(),
|
||||||
DestinationType.Cloud => new CloudDestiantion(dctx),
|
DestinationType.Main => GitDestination.CreateForGitea(dctx, project.RepoOwner, rctx.Args.Verbose).UpcastSuccess<GitDestination, IDestination, ReadableError>(),
|
||||||
|
DestinationType.Cloud => new CloudDestiantion(dctx).Ok<IDestination>(),
|
||||||
_ => throw new UnreachableException()
|
_ => throw new UnreachableException()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var destination = destinationResult.Unwrap(rctx);
|
||||||
|
|
||||||
var result = await destination.WaitForCompletion(ct);
|
var result = await destination.WaitForCompletion(ct);
|
||||||
lock(rctx) {
|
lock(rctx) {
|
||||||
if (result.Unwrap(rctx) is not null) {
|
if (result.Unwrap(rctx) is not null) {
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ internal class ProjectFile {
|
|||||||
set("PackageProjectUrl", "", required: false);
|
set("PackageProjectUrl", "", required: false);
|
||||||
set("RepositoryUrl", "", required: true);
|
set("RepositoryUrl", "", required: true);
|
||||||
set("PackageId", "", required: true);
|
set("PackageId", "", required: true);
|
||||||
|
set("RepositoryOwner", "", required: true);
|
||||||
|
|
||||||
if (failed.Count > 0) {
|
if (failed.Count > 0) {
|
||||||
error = string.Format(Exceptions.project_file_irreparable, Path, string.Join(", ", failed));
|
error = string.Format(Exceptions.project_file_irreparable, Path, string.Join(", ", failed));
|
||||||
@@ -124,6 +125,10 @@ internal class ProjectFile {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetRepositoryOwner() {
|
||||||
|
return MainPropertyGroup.GetProperty("RepositoryOwner");
|
||||||
|
}
|
||||||
|
|
||||||
public List<PackageReference> GetPackageReferences() {
|
public List<PackageReference> GetPackageReferences() {
|
||||||
return Project.ItemGroups
|
return Project.ItemGroups
|
||||||
.SelectMany(g => g.Items)
|
.SelectMany(g => g.Items)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generated by TARGET FORGE — MSBuild publish target -->
|
||||||
|
<!-- Save as PublishAll.targets and <Import Project="PublishAll.targets" /> in your .csproj, -->
|
||||||
|
<!-- or paste the <Target> below directly into the .csproj. -->
|
||||||
|
<!-- Run: dotnet msbuild -t:PublishAll -->
|
||||||
|
<Project>
|
||||||
|
|
||||||
|
<Target Name="PublishAll">
|
||||||
|
<ItemGroup>
|
||||||
|
<Rid Include="win-x64;linux-x64;osx-x64;osx-arm64" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<MSBuild Projects="$(MSBuildProjectFullPath)"
|
||||||
|
Targets="Publish"
|
||||||
|
BuildInParallel="true"
|
||||||
|
Properties="Configuration=Release;
|
||||||
|
Platform=Any CPU;
|
||||||
|
TargetFramework=net9.0;
|
||||||
|
RuntimeIdentifier=%(Rid.Identity);
|
||||||
|
SelfContained=true;
|
||||||
|
PublishSingleFile=true;
|
||||||
|
PublishDir=bin\Release\publish\%(Rid.Identity)\" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- All four are overridable from the CLI: -p:ArchiveVersion=1.2.3 etc. -->
|
||||||
|
<ArchiveAppName Condition="'$(ArchiveAppName)' == ''">$(AssemblyName)</ArchiveAppName>
|
||||||
|
<ArchiveVersion Condition="'$(ArchiveVersion)' == ''">$(Version)</ArchiveVersion>
|
||||||
|
<ArchiveVersion Condition="'$(ArchiveVersion)' == ''">1.3.0</ArchiveVersion>
|
||||||
|
<ArchiveOutputDir Condition="'$(ArchiveOutputDir)' == ''">$(MSBuildProjectDirectory)\dist\</ArchiveOutputDir>
|
||||||
|
<PublishBaseDir Condition="'$(PublishBaseDir)' == ''">$(MSBuildProjectDirectory)\bin\Release\publish\</PublishBaseDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="Archive" DependsOnTargets="PublishAll">
|
||||||
|
<MakeDir Directories="$(ArchiveOutputDir)" />
|
||||||
|
|
||||||
|
<ZipDirectory SourceDirectory="$(PublishBaseDir)%(Rid.Identity)\"
|
||||||
|
DestinationFile="$(ArchiveOutputDir)$(ArchiveAppName)-$(ArchiveVersion)-%(Rid.Identity).zip"
|
||||||
|
Overwrite="true" />
|
||||||
|
|
||||||
|
<Exec Command='tar -czf "$(ArchiveOutputDir)$(ArchiveAppName)-$(ArchiveVersion)-%(Rid.Identity).tar.gz" -C "$(PublishBaseDir)%(Rid.Identity)" .' />
|
||||||
|
|
||||||
|
<Message Importance="high" Text="Archived $(ArchiveAppName) $(ArchiveVersion) → $(ArchiveOutputDir)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -28,10 +28,36 @@ internal static class ResultExtensions {
|
|||||||
public static async Task<T> Unwrap<T>(this Task<Result<T, ReadableError>> result, Program.RunContext? rctx = null) {
|
public static async Task<T> Unwrap<T>(this Task<Result<T, ReadableError>> result, Program.RunContext? rctx = null) {
|
||||||
return (await result).Unwrap(rctx);
|
return (await result).Unwrap(rctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Result<TTo, ETo> Cast<TFrom, EFrom, TTo, ETo>(this Result<TFrom, EFrom> result) where TTo : notnull, TFrom where ETo: notnull, EFrom {
|
||||||
|
return result switch {
|
||||||
|
TFrom tfrom => ((TTo)tfrom).Ok(),
|
||||||
|
EFrom efrom => ((ETo)efrom),
|
||||||
|
_ => throw new UnreachableException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<TTo, ETo> Upcast<TFrom, EFrom, TTo, ETo>(this Result<TFrom, EFrom> result)
|
||||||
|
where TFrom : TTo
|
||||||
|
where EFrom : ETo
|
||||||
|
{
|
||||||
|
return result switch {
|
||||||
|
TFrom tfrom => ((TTo)tfrom).Ok(), // Foo -> IFoo, implicit upcast, can't throw
|
||||||
|
EFrom efrom => ((ETo)efrom),
|
||||||
|
_ => throw new UnreachableException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<TTo, E> CastSuccess<TFrom, TTo, E>(this Result<TFrom, E> result) where TTo : notnull, TFrom where E: notnull
|
||||||
|
=> Cast<TFrom, E, TTo, E>(result);
|
||||||
|
|
||||||
|
public static Result<TTo, E> UpcastSuccess<TFrom, TTo, E>(this Result<TFrom, E> result) where TFrom : notnull, TTo where E: notnull
|
||||||
|
=> Upcast<TFrom, E, TTo, E>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class ObjectExtensions {
|
internal static class ObjectExtensions {
|
||||||
public static Ok<T> Ok<T>(this T any) {
|
public static Ok<T> Ok<T>(this T any) {
|
||||||
return new Ok<T>(any);
|
return new Ok<T>(any);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="PublishAll.targets" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64;osx-x64</RuntimeIdentifiers>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
@@ -9,7 +14,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="aeqw89.xml.ProjectFile" Version="1.0.3" />
|
<PackageReference Include="aeqw89.xml.ProjectFile" Version="2.0.0" />
|
||||||
<PackageReference Include="Aigamo.ResXGenerator" Version="4.3.0">
|
<PackageReference Include="Aigamo.ResXGenerator" Version="4.3.0">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
Reference in New Issue
Block a user