Files
MaaAssistantArknights/tools/MaaBuilder/Builder/BuildParameters.cs
2024-01-01 18:10:47 +08:00

269 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json.Linq;
using Nuke.Common;
using Nuke.Common.CI;
using Nuke.Common.CI.GitHubActions;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tools.Git;
using Serilog;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.RegularExpressions;
using MaaBuilder.Models;
using static Nuke.Common.Tools.VSWhere.VSWhereTasks;
using Nuke.Common.Tools.MSBuild;
using Nuke.Common.Utilities.Collections;
namespace MaaBuilder;
public partial class Build
{
#region Nuke
[CI] private readonly GitHubActions GitHubActions;
public static bool IsReleaseSimulation { get; set; }
#endregion Nuke
public class BuildParameters
{
#region
private static readonly Lazy<string> GetVsPath = new(() =>
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) is false)
{
return null;
}
var vsDirectory = VSWhere("-latest -nologo -property installationPath -format value -prerelease").FirstOrDefault().Text;
return string.IsNullOrWhiteSpace(vsDirectory) ? null : vsDirectory;
});
private readonly Func<string, string> GetMsBuildPath = vsPath =>
{
var msBuildExe = Path.Combine(vsPath, @"MSBuild\Current\Bin\MSBuild.exe");
if (File.Exists(msBuildExe) is false)
{
msBuildExe = Path.Combine(vsPath, @"MSBuild\15.0\Bin\MSBuild.exe");
}
return File.Exists(msBuildExe) ? msBuildExe : null;
};
#endregion
// 工具链
public AbsolutePath MsBuildPath { get; }
public AbsolutePath VisualStudioPath { get; }
// 仓库
public string MainRepo { get; }
public string MasterBranchRef { get; }
public string DevBranchRef { get; }
public string ReleaseTagRefPrefix { get; }
// 路径
public AbsolutePath BuildOutput { get; }
public AbsolutePath ArtifactOutput { get; }
public AbsolutePath MaaChangelogFile { get; }
// 项目
public Project MaaCoreProject { get; }
public Project MaaWpfProject { get; }
public Project MaaSyncResProject { get; }
// 配置
public string BuildTime { get; }
public string CommitHash { get; }
public string CommitHashFull { get; }
public string TargetPlatform { get; }
public List<Package> Packages { get; } = null;
// CI
public bool IsGitHubActions { get; }
public bool IsPullRequest { get; }
public bool IsWorkflowDispatch { get; }
public bool IsPreRelease { get; }
public string GitHubPersonalAccessToken { get; }
public string GhActionWdReason { get; }
public string GhActionWdRsTagName { get; }
public ActionConfiguration GhActionName { get; }
public string GhBranch { get; }
public string GhPullRequestId { get; }
public string GhTag { get; }
public BuildParameters(Build b)
{
// 工具链
var vs = GetVsPath.Value;
Assert.True(vs is not null, "找不到 Visual Studio");
VisualStudioPath = (AbsolutePath)vs;
var msbuild = GetMsBuildPath.Invoke(VisualStudioPath);
Assert.True(msbuild is not null, "找不到 MSBuild");
MsBuildPath = (AbsolutePath)msbuild;
TargetPlatform = Environment.GetEnvironmentVariable("MAABUILDER_TARGET_PLATFORM") ?? HostPlatform;
// 仓库
MainRepo = "MaaAssistantArknights/MaaAssistantArknights";
MasterBranchRef = "refs/heads/master";
DevBranchRef = "refs/heads/dev";
ReleaseTagRefPrefix = "refs/tags/v";
// 路径
BuildOutput = RootDirectory / TargetPlatform;
ArtifactOutput = RootDirectory / "artifacts";
MaaChangelogFile = RootDirectory / "CHANGELOG.md";
// 项目
var maaSolution = ProjectModelTasks.ParseSolution(RootDirectory / "MAA.sln");
Assert.True(maaSolution is not null, "无法载入 MAA.sln");
MaaCoreProject = maaSolution.GetProject("MaaCore");
MaaWpfProject = maaSolution.GetProject("MaaWpfGui");
MaaSyncResProject = maaSolution.GetProject("SyncRes");
// 配置
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("zh-Hans-CN");
BuildTime = DateTimeOffset.UtcNow.ToLocalTime().ToString("yyyy-MM-dd-HH-mm-ss");
CommitHash = GitTasks.GitCurrentCommit();
Assert.True(CommitHash is not null, "Commit Hash 为 Null");
CommitHashFull = CommitHash;
CommitHash = CommitHash[..7];
var packageDefinitionFile = RootDirectory / "package-definition.json";
var stream = File.OpenRead(packageDefinitionFile);
var model = JsonSerializer.Deserialize<List<Package>>(stream);
stream.Close();
Packages = model;
// CI
IsGitHubActions = b.GitHubActions is not null;
if (IsGitHubActions is false)
{
return;
}
GhActionName = (ActionConfiguration)b.GitHubActions!.Workflow;
Assert.True(GhActionName is not null, $"GitHub Actions Workflow 名 {b.GitHubActions.Workflow} 无法转换为 ActionConfiguration");
Assert.False(string.IsNullOrEmpty(b.GitHubActions.Ref), "Ref 为 Null");
GitHubPersonalAccessToken = Environment.GetEnvironmentVariable("PUBLISH_GH_PAT");
if (b.GitHubActions.Ref.StartsWith(ReleaseTagRefPrefix))
{
var tag = $"v{b.GitHubActions.Ref.Replace(ReleaseTagRefPrefix, "")}";
var pattern = @"^v((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)";
var match = Regex.Match(tag, pattern);
if (match.Success)
{
GhTag = tag;
var preReleasePattern = @"^v((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))(-)";
var preReleaseMatch = Regex.Match(tag, preReleasePattern);
IsPreRelease = preReleaseMatch.Success;
}
else
{
Assert.Fail("Tag 与 SemVer 不匹配");
}
}
else if (b.GitHubActions.Ref.StartsWith("refs/heads/"))
{
GhBranch = b.GitHubActions.Ref.Replace("refs/heads/", "");
}
else if (b.GitHubActions.IsPullRequest)
{
IsPullRequest = true;
GhPullRequestId = b.GitHubActions.Ref;
}
else
{
Log.Warning("未知的 Ref{Ref}", b.GitHubActions.Ref ?? "Null");
}
var ghEvent = b.GitHubActions.GitHubEvent;
if (IsGitHubActions)
{
Console.WriteLine("::group::GitHub Event");
Log.Information("GitHub Event{Event}", ghEvent.ToString());
Console.WriteLine("::endgroup::");
}
if (ghEvent.ContainsKey("inputs") && !ghEvent["inputs"].IsNullOrEmpty())
{
IsWorkflowDispatch = true;
var inputs = (JObject)ghEvent["inputs"];
foreach (var (k, v) in inputs)
{
switch (k)
{
case "Reason":
GhActionWdReason = v.ToString();
break;
case "ReleaseSimulation":
var tn = v.ToString();
if (string.IsNullOrEmpty(tn) || tn == "none")
{
break;
}
IsReleaseSimulation = true;
GhActionWdRsTagName = tn;
break;
}
}
}
if (b.GitHubActions.BaseRef is not null)
{
// Fork
MainRepo = b.GitHubActions.Repository;
}
// 若是 DevBuildBranch 必须不为 Master或者是 PR 至 Dev又或者是手动触发
if (GhActionName == ActionConfiguration.DevBuild)
{
if (IsWorkflowDispatch)
{
Assert.True(GhBranch is not null, "DevBuild -> Workflow DispatchBranch 为 Null");
}
else if (IsPullRequest)
{
Assert.True(GhPullRequestId is not null, "DevBuild -> Pull RequestPull Request Id 为 Null");
}
else
{
Assert.True(GhBranch != MasterBranch, "DevBuild -> Auto TriggeredBranch 为 master");
}
}
// 若是 ReleaseMaaTag 必须存在PAT 必须存在
if (GhActionName == ActionConfiguration.ReleaseMaa)
{
Assert.True(GhTag is not null, "ReleaseMaa -> Auto TriggeredTag 为 Null");
Assert.True(GitHubPersonalAccessToken is not null, "ReleaseMaa -> Auto TriggeredPAT 为 Null");
}
}
}
}