Update BuildGeneratorEditorWindow.cs

This commit is contained in:
Syntriax 2025-01-11 17:58:31 +03:00
parent 883472fd3d
commit 07b34535fb

View File

@ -1,282 +1,326 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using UnityEditor; using UnityEditor;
using UnityEngine;
using UnityEngine;
public class BuildGeneratorEditorWindow : EditorWindow
{ public class BuildGeneratorEditorWindow : EditorWindow
private VersionDefinition versionDefinition = default; {
private VersionDefinition editorVersion = default;
[MenuItem("Window/Build Generator")] private VersionDefinition gitVersion = default;
private static void ShowWindow()
{ [MenuItem("Window/Build Generator")]
BuildGeneratorEditorWindow window = GetWindow<BuildGeneratorEditorWindow>(); private static void ShowWindow()
window.titleContent = new GUIContent("Build Generator"); {
BuildGeneratorEditorWindow window = GetWindow<BuildGeneratorEditorWindow>();
window.versionDefinition = new(PlayerSettings.bundleVersion); window.titleContent = new GUIContent("Build Generator");
window.Show(); window.editorVersion = new(PlayerSettings.bundleVersion);
} try { window.gitVersion = GitProcess.GetLatestBuildVersion(); } catch { }
private void OnGUI() window.Show();
{ }
EditorGUILayout.LabelField($"Current Version: {versionDefinition.Version}");
EditorGUILayout.LabelField($"Build Number: {versionDefinition.BuildNumber}"); private void OnGUI()
{
// EditorGUILayout.BeginHorizontal(); if (GUILayout.Button($"Re-evaluate versions"))
// if (IncrementButton("Major", versionDefinition.IncreaseMajor())) {
// ApplyVersion(versionDefinition.IncreaseMajor()); editorVersion = new(PlayerSettings.bundleVersion);
gitVersion = GitProcess.GetLatestBuildVersion();
// if (IncrementButton("Minor", versionDefinition.IncreaseMinor())) }
// ApplyVersion(versionDefinition.IncreaseMinor());
EditorGUILayout.Space();
// if (IncrementButton("Patch", versionDefinition.IncreasePatch()))
// ApplyVersion(versionDefinition.IncreasePatch()); EditorGUILayout.BeginHorizontal();
// if (IncrementButton("Release Candidate", versionDefinition.IncreaseReleaseCandidate())) EditorGUILayout.BeginVertical();
// ApplyVersion(versionDefinition.IncreaseReleaseCandidate()); if (GUILayout.Button($"Create Release")) CommitVersion(GitProcess.GetUpcomingReleaseVersion());
if (GUILayout.Button($"Create Release Candidate")) CommitVersion(GitProcess.GetUpcomingReleaseCandidateVersion());
// EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical();
if (GUILayout.Button($"Evaluate Version from git")) versionDefinition = GitProcess.GetUpcomingReleaseCandidateVersion(); EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField($"Editor Version: {editorVersion} ({editorVersion.BuildNumber})");
if (GUILayout.Button($"Commit Release Candidate")) CommitVersion(GitProcess.GetUpcomingReleaseCandidateVersion()); EditorGUILayout.LabelField($"Git Version: {editorVersion} ({editorVersion.BuildNumber})");
if (GUILayout.Button($"Commit Release")) CommitVersion(GitProcess.GetUpcomingReleaseVersion()); EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
} EditorGUILayout.EndHorizontal();
private void CommitVersion(VersionDefinition versionDefinition) EditorGUILayout.Space();
{ if (GUILayout.Button($"Push All")) { GitProcess.Push(); GitProcess.PushTags(); }
ApplyVersion(versionDefinition);
GitProcess.Add("ProjectSettings\\ProjectSettings.asset"); // EditorGUILayout.BeginHorizontal();
GitProcess.Add("Assets\\Settings\\Build Profiles\\**"); // if (IncrementButton("Major", versionDefinition.IncreaseMajor()))
GitProcess.Commit($"chore: Bump Version to {versionDefinition}"); // CommitVersion(versionDefinition.IncreaseMajor());
GitProcess.CreateVersionTag(versionDefinition);
} // if (IncrementButton("Minor", versionDefinition.IncreaseMinor()))
// CommitVersion(versionDefinition.IncreaseMinor());
private bool IncrementButton(string fieldName, VersionDefinition resultDefinition)
{ // if (IncrementButton("Patch", versionDefinition.IncreasePatch()))
EditorGUILayout.BeginVertical(); // CommitVersion(versionDefinition.IncreasePatch());
bool isButtonPressed = GUILayout.Button($"Add Incremental {fieldName}"); // if (IncrementButton("Release Candidate", versionDefinition.IncreaseReleaseCandidate()))
EditorGUILayout.LabelField($"{versionDefinition} -> {resultDefinition}", new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter }); // CommitVersion(versionDefinition.IncreaseReleaseCandidate());
EditorGUILayout.EndVertical(); // EditorGUILayout.EndHorizontal();
}
return isButtonPressed && EditorUtility.DisplayDialog("Increment Confirmation", $"Are you sure to add an incremental {fieldName} version?", "Yes", "Cancel");
} private void CommitVersion(VersionDefinition versionDefinition)
{
private void ApplyVersion(VersionDefinition versionDefinition) if (this.editorVersion >= versionDefinition)
{ {
this.versionDefinition = this.versionDefinition >= versionDefinition ? this.versionDefinition : versionDefinition; EditorUtility.DisplayDialog(
PlayerSettings.Android.bundleVersionCode = versionDefinition.BuildNumber; "Release Conflict",
PlayerSettings.iOS.buildNumber = versionDefinition.BuildNumber.ToString(); $"You can't create a new version because the old version({this.editorVersion}) is either higher or the same as the new version({versionDefinition}). Please make new commits to create new releases.",
PlayerSettings.bundleVersion = versionDefinition.ToString(); "Return");
AssetDatabase.SaveAssets(); return;
} }
private struct VersionDefinition if (EditorUtility.DisplayDialog(
{ "Release Confirmation",
public const uint MAX_VALUE = 99; $"Are you sure to commit a new incremental version of {versionDefinition}?",
"Yes",
public const uint DEFAULT_MAJOR = 0; "Cancel")
public const uint DEFAULT_MINOR = 0; )
public const uint DEFAULT_PATCH = 0; return;
public const uint DEFAULT_RELEASE_CANDIDATE = 1;
public const uint RELEASE_RC_VALUE = 99; ApplyVersion(versionDefinition);
GitProcess.Add("ProjectSettings\\ProjectSettings.asset");
private readonly uint _major; GitProcess.Add("Assets\\Settings\\Build Profiles\\**");
private readonly uint _minor; GitProcess.Commit($"chore: Bump Version to {versionDefinition}");
private readonly uint _patch; GitProcess.CreateTag(versionDefinition);
private readonly uint _releaseCandidate; GitProcess.PushTag(versionDefinition);
}
public readonly uint Major => _major > MAX_VALUE ? MAX_VALUE : _major;
public readonly uint Minor => _minor > MAX_VALUE ? MAX_VALUE : _minor; private bool IncrementButton(string fieldName, VersionDefinition resultDefinition)
public readonly uint Patch => _patch > MAX_VALUE ? MAX_VALUE : _patch; {
public readonly uint ReleaseCandidate => _releaseCandidate > MAX_VALUE ? MAX_VALUE : _releaseCandidate; EditorGUILayout.BeginVertical();
public readonly bool IsRelease => ReleaseCandidate == RELEASE_RC_VALUE; bool isButtonPressed = GUILayout.Button($"Add Incremental {fieldName}");
EditorGUILayout.LabelField($"{editorVersion} -> {resultDefinition}", new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter });
public VersionDefinition(uint? major = null, uint? minor = null, uint? patch = null, uint? releaseCandidate = null)
{ EditorGUILayout.EndVertical();
_major = major ?? DEFAULT_MAJOR;
_minor = minor ?? DEFAULT_MINOR; return isButtonPressed && EditorUtility.DisplayDialog("Increment Confirmation", $"Are you sure to add an incremental {fieldName} version?", "Yes", "Cancel");
_patch = patch ?? DEFAULT_PATCH; }
_releaseCandidate = releaseCandidate ?? DEFAULT_RELEASE_CANDIDATE;
private void ApplyVersion(VersionDefinition versionDefinition)
if (_major == 0 && _minor == 0) {
_minor = 1; this.editorVersion = versionDefinition;
} PlayerSettings.Android.bundleVersionCode = versionDefinition.BuildNumber;
PlayerSettings.iOS.buildNumber = versionDefinition.BuildNumber.ToString();
public VersionDefinition(string versionString) PlayerSettings.bundleVersion = versionDefinition.ToString();
{ AssetDatabase.SaveAssets();
if (versionString.StartsWith('v')) }
versionString = versionString[1..];
private struct VersionDefinition
_major = DEFAULT_MAJOR; {
_minor = DEFAULT_MINOR; public const int MAX_VALUE = 99;
_patch = DEFAULT_PATCH; public const string BUILD_NUMBER_FORMAT = "00";
_releaseCandidate = RELEASE_RC_VALUE;
public const int DEFAULT_MAJOR = 0;
string[] releaseCandidateVersionStrings = versionString.Split("-rc"); public const int DEFAULT_MINOR = 0;
string[] versionNumbers = releaseCandidateVersionStrings[0].Split('.'); public const int DEFAULT_PATCH = 0;
public const int DEFAULT_RELEASE_CANDIDATE = 1;
if (versionNumbers.Length > 0 && uint.TryParse(versionNumbers[0], out uint major)) _major = major; public const int RELEASE_RC_VALUE = 99;
if (versionNumbers.Length > 1 && uint.TryParse(versionNumbers[1], out uint minor)) _minor = minor;
if (versionNumbers.Length > 2 && uint.TryParse(versionNumbers[2], out uint patch)) _patch = patch; private readonly int _major;
if (releaseCandidateVersionStrings.Length > 1 && uint.TryParse(releaseCandidateVersionStrings[1], out uint releaseCandidate)) _releaseCandidate = releaseCandidate; private readonly int _minor;
private readonly int _patch;
if (Major == 0 && Minor == 0) private readonly int _releaseCandidate;
Minor = ReleaseCandidate = 1;
} public readonly int Major => _major > MAX_VALUE ? MAX_VALUE : _major;
public readonly int Minor => _minor > MAX_VALUE ? MAX_VALUE : _minor;
public readonly VersionDefinition IncreaseMajor() => new(Major + 1, DEFAULT_MINOR, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE); public readonly int Patch => _patch > MAX_VALUE ? MAX_VALUE : _patch;
public readonly VersionDefinition IncreaseMinor() => new(Major, Minor + 1, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE); public readonly int ReleaseCandidate => _releaseCandidate > MAX_VALUE ? MAX_VALUE : _releaseCandidate;
public readonly VersionDefinition IncreasePatch() => new(Major, Minor, Patch + 1, DEFAULT_RELEASE_CANDIDATE);
public readonly VersionDefinition IncreaseReleaseCandidate() => new(Major, Minor, Patch, ReleaseCandidate + 1); public readonly bool IsRelease => ReleaseCandidate == RELEASE_RC_VALUE;
public readonly VersionDefinition ToReleaseVersion() => new(Major, Minor, Patch, RELEASE_RC_VALUE);
public VersionDefinition(int? major = null, int? minor = null, int? patch = null, int? releaseCandidate = null)
public readonly uint BuildNumber => uint.Parse($"{Major:00}{Minor:00}{Patch:00}{ReleaseCandidate:00}"); {
_major = major ?? DEFAULT_MAJOR;
public override readonly string ToString() _minor = minor ?? DEFAULT_MINOR;
{ _patch = patch ?? DEFAULT_PATCH;
if (IsRelease) _releaseCandidate = releaseCandidate ?? DEFAULT_RELEASE_CANDIDATE;
return $"{Major}.{Minor}.{Patch}";
return $"{Major}.{Minor}.{Patch}-rc{ReleaseCandidate}"; if (_major == 0 && _minor == 0)
} _minor = _releaseCandidate = 1;
}
public static bool operator >(VersionDefinition left, VersionDefinition right) => left.BuildNumber > right.BuildNumber;
public static bool operator <(VersionDefinition left, VersionDefinition right) => left.BuildNumber < right.BuildNumber; public VersionDefinition(string versionString)
public static bool operator >=(VersionDefinition left, VersionDefinition right) => left.BuildNumber >= right.BuildNumber; {
public static bool operator <=(VersionDefinition left, VersionDefinition right) => left.BuildNumber <= right.BuildNumber; if (versionString.StartsWith('v'))
public static bool operator ==(VersionDefinition left, VersionDefinition right) => left.BuildNumber == right.BuildNumber; versionString = versionString[1..];
public static bool operator !=(VersionDefinition left, VersionDefinition right) => left.BuildNumber != right.BuildNumber;
} _major = DEFAULT_MAJOR;
_minor = DEFAULT_MINOR;
private static class GitProcess _patch = DEFAULT_PATCH;
{ _releaseCandidate = RELEASE_RC_VALUE;
public static VersionDefinition GetLatestBuildVersion() => new(GetLatestBuildVersionString());
public static VersionDefinition GetUpcomingReleaseVersion() => GetUpcomingReleaseCandidateVersion().ToReleaseVersion(); string[] releaseCandidateVersionStrings = versionString.Split("-rc");
public static VersionDefinition GetUpcomingReleaseCandidateVersion() string[] versionNumbers = releaseCandidateVersionStrings[0].Split('.');
{
VersionDefinition latestVersionDefinition = GetLatestBuildVersion(); if (versionNumbers.Length > 0 && int.TryParse(versionNumbers[0], out int major)) _major = major;
string[] commits = GetCommitsSinceLastTag(); if (versionNumbers.Length > 1 && int.TryParse(versionNumbers[1], out int minor)) _minor = minor;
return ApplySemVer(latestVersionDefinition, commits); if (versionNumbers.Length > 2 && int.TryParse(versionNumbers[2], out int patch)) _patch = patch;
} if (releaseCandidateVersionStrings.Length > 1 && int.TryParse(releaseCandidateVersionStrings[1], out int releaseCandidate)) _releaseCandidate = releaseCandidate;
public static VersionDefinition GetVersion(string version, IList<string> gitLogs) if (_major == 0 && _minor == 0)
=> ApplySemVer(new(version), gitLogs); _minor = _releaseCandidate = 1;
}
public static VersionDefinition ApplySemVer(VersionDefinition latestVersionDefinition, IList<string> commits)
{ public readonly VersionDefinition IncreaseMajor() => new(Major + 1, DEFAULT_MINOR, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE);
VersionDefinition result = latestVersionDefinition.IsRelease ? latestVersionDefinition.IncreasePatch() : latestVersionDefinition; public readonly VersionDefinition IncreaseMinor() => new(Major, Minor + 1, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE);
for (int i = commits.Count - 1; i >= 0; i--) public readonly VersionDefinition IncreasePatch() => new(Major, Minor, Patch + 1, DEFAULT_RELEASE_CANDIDATE);
{ public readonly VersionDefinition IncreaseReleaseCandidate() => new(Major, Minor, Patch, ReleaseCandidate + 1);
string line = commits[i]; public readonly VersionDefinition ToReleaseVersion() => new(Major, Minor, Patch, RELEASE_RC_VALUE);
if (string.IsNullOrWhiteSpace(line))
continue; public readonly int BuildNumber => int.Parse($"{Major.ToString(BUILD_NUMBER_FORMAT)}{Minor.ToString(BUILD_NUMBER_FORMAT)}{Patch.ToString(BUILD_NUMBER_FORMAT)}{ReleaseCandidate.ToString(BUILD_NUMBER_FORMAT)}");
string commitTitle = line.Length > 9 ? line[9..] : line; public override readonly string ToString()
if (commitTitle.StartsWith("breaking change", StringComparison.InvariantCultureIgnoreCase)) {
{ if (IsRelease)
result = result.IncreaseMajor(); return $"{Major}.{Minor}.{Patch}";
break; return $"{Major}.{Minor}.{Patch}-rc{ReleaseCandidate}";
} }
if (latestVersionDefinition.Minor != result.Minor) public static bool operator >(VersionDefinition left, VersionDefinition right) => left.BuildNumber > right.BuildNumber;
continue; public static bool operator <(VersionDefinition left, VersionDefinition right) => left.BuildNumber < right.BuildNumber;
public static bool operator >=(VersionDefinition left, VersionDefinition right) => left.BuildNumber >= right.BuildNumber;
if (commitTitle.StartsWith("feat", StringComparison.OrdinalIgnoreCase)) public static bool operator <=(VersionDefinition left, VersionDefinition right) => left.BuildNumber <= right.BuildNumber;
{ public static bool operator ==(VersionDefinition left, VersionDefinition right) => left.BuildNumber == right.BuildNumber;
result = result.IncreaseMinor(); public static bool operator !=(VersionDefinition left, VersionDefinition right) => left.BuildNumber != right.BuildNumber;
continue;
} public override readonly bool Equals(object obj)
=> obj is VersionDefinition versionDefinition && BuildNumber == versionDefinition.BuildNumber;
if (latestVersionDefinition.Patch != result.Patch)
continue; public override readonly int GetHashCode()
=> HashCode.Combine(Major, Minor, Patch, ReleaseCandidate);
if (commitTitle.StartsWith("fix", StringComparison.OrdinalIgnoreCase)) }
{
result = result.IncreasePatch(); private static class GitProcess
continue; {
} public static VersionDefinition GetLatestBuildVersion() => new(GetLatestBuildVersionString());
public static VersionDefinition GetUpcomingReleaseVersion() => GetUpcomingReleaseCandidateVersion().ToReleaseVersion();
if (latestVersionDefinition.ReleaseCandidate == result.ReleaseCandidate) public static VersionDefinition GetUpcomingReleaseCandidateVersion()
result = result.IncreaseReleaseCandidate(); {
} VersionDefinition latestVersionDefinition = GetLatestBuildVersion();
string[] commits = GetCommitsSinceLastTag();
return result; return ApplySemVer(latestVersionDefinition, commits);
} }
public static string GetLatestBuildVersionString() public static VersionDefinition GetVersion(string version, IList<string> gitLogs)
=> RunGitCommand($"describe --tags --abbrev=0"); => ApplySemVer(new(version), gitLogs);
public static string[] GetCommits() public static VersionDefinition ApplySemVer(VersionDefinition latestVersionDefinition, IList<string> commits)
=> RunGitCommand("log --oneline").Replace("\r", "").Split('\n'); {
VersionDefinition result = latestVersionDefinition.IsRelease ? latestVersionDefinition.IncreasePatch() : latestVersionDefinition;
public static string[] GetCommitsSinceLastTag() for (int i = commits.Count - 1; i >= 0; i--)
=> RunGitCommand($"log {GetLatestBuildVersionString()}..HEAD --oneline").Replace("\r", "").Split('\n'); {
string line = commits[i];
public static string CreateVersionTag(VersionDefinition versionDefinition) if (string.IsNullOrWhiteSpace(line))
=> CreateTag($"v{versionDefinition.Version}", $"{(versionDefinition.IsRelease ? "Release" : "Build")} {versionDefinition.Version} with build number: {versionDefinition.BuildNumber}\""); continue;
public static string Push() string commitTitle = line.Length > 9 ? line[9..] : line;
=> RunGitCommand($"push"); if (commitTitle.StartsWith("breaking change", StringComparison.InvariantCultureIgnoreCase))
{
public static string Add(IList<string> files) result = result.IncreaseMajor();
=> RunGitCommand($"add \"{string.Join("\" \"", files)}\""); break;
}
public static string Add(string file)
=> RunGitCommand($"add \"{file}\""); if (latestVersionDefinition.Minor != result.Minor)
continue;
public static string Commit(string message)
=> RunGitCommand($"commit -m \"{message}\""); if (commitTitle.StartsWith("feat", StringComparison.OrdinalIgnoreCase))
{
public static string PushTags() result = result.IncreaseMinor();
=> RunGitCommand($"tag --push"); continue;
}
public static string PushVersionTag(VersionDefinition versionDefinition)
=> RunGitCommand($"push origin tag v{versionDefinition.Version}"); if (latestVersionDefinition.Patch != result.Patch)
continue;
public static string CreateTag(string title, string message)
=> RunGitCommand($"tag -a {title} -m \"{message}"); if (commitTitle.StartsWith("fix", StringComparison.OrdinalIgnoreCase))
{
public static string Unstage(IList<string> files) result = result.IncreasePatch();
=> RunGitCommand($"reset \"{string.Join("\" \"", files)}\""); continue;
}
public static string Unstage(string file)
=> RunGitCommand($"reset \"{file}\""); if (latestVersionDefinition.ReleaseCandidate == result.ReleaseCandidate)
result = result.IncreaseReleaseCandidate();
public static string Unstage() }
=> RunGitCommand($"reset");
return result;
private static string RunGitCommand(string gitArgs) }
{
ProcessStartInfo processStartInfo = new() public static string GetLatestBuildVersionString()
{ => RunGitCommand($"describe --tags --abbrev=0");
FileName = "git",
Arguments = gitArgs, public static string[] GetCommits()
RedirectStandardOutput = true, => RunGitCommand("log --oneline").Replace("\r", "").Split('\n');
UseShellExecute = false,
CreateNoWindow = true public static string[] GetCommitsSinceLastTag()
}; => RunGitCommand($"log {GetLatestBuildVersionString()}..HEAD --oneline").Replace("\r", "").Split('\n');
try public static string CreateTag(VersionDefinition versionDefinition)
{ => CreateTag($"v{versionDefinition}", $"{(versionDefinition.IsRelease ? "Release" : "Build")} {versionDefinition} with build number: {versionDefinition.BuildNumber}\"");
Process process = Process.Start(processStartInfo);
string output = process.StandardOutput.ReadToEnd(); public static string Push()
if (output.EndsWith('\n')) output = output[0..^1]; => RunGitCommand($"push");
if (output.EndsWith('\r')) output = output[0..^1];
process.WaitForExit(); public static string Add(IList<string> files)
return output; => RunGitCommand($"add \"{string.Join("\" \"", files)}\"");
}
catch (Exception ex) public static string Add(string file)
{ => RunGitCommand($"add \"{file}\"");
Console.WriteLine("An error occurred: " + ex.Message);
throw; public static string Commit(string message)
} => RunGitCommand($"commit -m \"{message}\"");
}
} public static string PushTags()
} => RunGitCommand($"push --tags");
public static string PushTag(VersionDefinition versionDefinition, string remote = "origin")
=> RunGitCommand($"push {remote} tag v{versionDefinition}");
public static string CreateTag(string title, string message)
=> RunGitCommand($"tag -a {title} -m \"{message}");
public static string Unstage(IList<string> files)
=> RunGitCommand($"reset \"{string.Join("\" \"", files)}\"");
public static string Unstage(string file)
=> RunGitCommand($"reset \"{file}\"");
public static string Unstage()
=> RunGitCommand($"reset");
private static string RunGitCommand(string gitArgs)
{
ProcessStartInfo processStartInfo = new()
{
FileName = "git",
Arguments = gitArgs,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
try
{
Process process = Process.Start(processStartInfo);
string output = process.StandardOutput.ReadToEnd();
if (output.EndsWith('\n')) output = output[0..^1];
if (output.EndsWith('\r')) output = output[0..^1];
process.WaitForExit();
return output;
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: " + ex.Message);
throw;
}
}
}
}