283 lines
12 KiB
C#
283 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
public class BuildGeneratorEditorWindow : EditorWindow
|
|
{
|
|
private VersionDefinition versionDefinition = default;
|
|
|
|
[MenuItem("Window/Build Generator")]
|
|
private static void ShowWindow()
|
|
{
|
|
BuildGeneratorEditorWindow window = GetWindow<BuildGeneratorEditorWindow>();
|
|
window.titleContent = new GUIContent("Build Generator");
|
|
|
|
window.versionDefinition = new(PlayerSettings.bundleVersion);
|
|
|
|
window.Show();
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
EditorGUILayout.LabelField($"Current Version: {versionDefinition.Version}");
|
|
EditorGUILayout.LabelField($"Build Number: {versionDefinition.BuildNumber}");
|
|
|
|
// EditorGUILayout.BeginHorizontal();
|
|
// if (IncrementButton("Major", versionDefinition.IncreaseMajor()))
|
|
// ApplyVersion(versionDefinition.IncreaseMajor());
|
|
|
|
// if (IncrementButton("Minor", versionDefinition.IncreaseMinor()))
|
|
// ApplyVersion(versionDefinition.IncreaseMinor());
|
|
|
|
// if (IncrementButton("Patch", versionDefinition.IncreasePatch()))
|
|
// ApplyVersion(versionDefinition.IncreasePatch());
|
|
|
|
// if (IncrementButton("Release Candidate", versionDefinition.IncreaseReleaseCandidate()))
|
|
// ApplyVersion(versionDefinition.IncreaseReleaseCandidate());
|
|
|
|
// EditorGUILayout.EndHorizontal();
|
|
|
|
if (GUILayout.Button($"Evaluate Version from git")) versionDefinition = GitProcess.GetUpcomingReleaseCandidateVersion();
|
|
EditorGUILayout.BeginHorizontal();
|
|
if (GUILayout.Button($"Commit Release Candidate")) CommitVersion(GitProcess.GetUpcomingReleaseCandidateVersion());
|
|
if (GUILayout.Button($"Commit Release")) CommitVersion(GitProcess.GetUpcomingReleaseVersion());
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
|
|
private void CommitVersion(VersionDefinition versionDefinition)
|
|
{
|
|
ApplyVersion(versionDefinition);
|
|
GitProcess.Add("ProjectSettings\\ProjectSettings.asset");
|
|
GitProcess.Add("Assets\\Settings\\Build Profiles\\**");
|
|
GitProcess.Commit($"chore: Bump Version to {versionDefinition}");
|
|
GitProcess.CreateVersionTag(versionDefinition);
|
|
}
|
|
|
|
private bool IncrementButton(string fieldName, VersionDefinition resultDefinition)
|
|
{
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
bool isButtonPressed = GUILayout.Button($"Add Incremental {fieldName}");
|
|
EditorGUILayout.LabelField($"{versionDefinition} -> {resultDefinition}", new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter });
|
|
|
|
EditorGUILayout.EndVertical();
|
|
|
|
return isButtonPressed && EditorUtility.DisplayDialog("Increment Confirmation", $"Are you sure to add an incremental {fieldName} version?", "Yes", "Cancel");
|
|
}
|
|
|
|
private void ApplyVersion(VersionDefinition versionDefinition)
|
|
{
|
|
this.versionDefinition = this.versionDefinition >= versionDefinition ? this.versionDefinition : versionDefinition;
|
|
PlayerSettings.Android.bundleVersionCode = versionDefinition.BuildNumber;
|
|
PlayerSettings.iOS.buildNumber = versionDefinition.BuildNumber.ToString();
|
|
PlayerSettings.bundleVersion = versionDefinition.ToString();
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
|
|
private struct VersionDefinition
|
|
{
|
|
public const uint MAX_VALUE = 99;
|
|
|
|
public const uint DEFAULT_MAJOR = 0;
|
|
public const uint DEFAULT_MINOR = 0;
|
|
public const uint DEFAULT_PATCH = 0;
|
|
public const uint DEFAULT_RELEASE_CANDIDATE = 1;
|
|
public const uint RELEASE_RC_VALUE = 99;
|
|
|
|
private readonly uint _major;
|
|
private readonly uint _minor;
|
|
private readonly uint _patch;
|
|
private readonly uint _releaseCandidate;
|
|
|
|
public readonly uint Major => _major > MAX_VALUE ? MAX_VALUE : _major;
|
|
public readonly uint Minor => _minor > MAX_VALUE ? MAX_VALUE : _minor;
|
|
public readonly uint Patch => _patch > MAX_VALUE ? MAX_VALUE : _patch;
|
|
public readonly uint ReleaseCandidate => _releaseCandidate > MAX_VALUE ? MAX_VALUE : _releaseCandidate;
|
|
|
|
public readonly bool IsRelease => ReleaseCandidate == RELEASE_RC_VALUE;
|
|
|
|
public VersionDefinition(uint? major = null, uint? minor = null, uint? patch = null, uint? releaseCandidate = null)
|
|
{
|
|
_major = major ?? DEFAULT_MAJOR;
|
|
_minor = minor ?? DEFAULT_MINOR;
|
|
_patch = patch ?? DEFAULT_PATCH;
|
|
_releaseCandidate = releaseCandidate ?? DEFAULT_RELEASE_CANDIDATE;
|
|
|
|
if (_major == 0 && _minor == 0)
|
|
_minor = 1;
|
|
}
|
|
|
|
public VersionDefinition(string versionString)
|
|
{
|
|
if (versionString.StartsWith('v'))
|
|
versionString = versionString[1..];
|
|
|
|
_major = DEFAULT_MAJOR;
|
|
_minor = DEFAULT_MINOR;
|
|
_patch = DEFAULT_PATCH;
|
|
_releaseCandidate = RELEASE_RC_VALUE;
|
|
|
|
string[] releaseCandidateVersionStrings = versionString.Split("-rc");
|
|
string[] versionNumbers = releaseCandidateVersionStrings[0].Split('.');
|
|
|
|
if (versionNumbers.Length > 0 && uint.TryParse(versionNumbers[0], out uint major)) _major = major;
|
|
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;
|
|
if (releaseCandidateVersionStrings.Length > 1 && uint.TryParse(releaseCandidateVersionStrings[1], out uint releaseCandidate)) _releaseCandidate = releaseCandidate;
|
|
|
|
if (Major == 0 && Minor == 0)
|
|
Minor = ReleaseCandidate = 1;
|
|
}
|
|
|
|
public readonly VersionDefinition IncreaseMajor() => new(Major + 1, DEFAULT_MINOR, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE);
|
|
public readonly VersionDefinition IncreaseMinor() => new(Major, Minor + 1, DEFAULT_PATCH, DEFAULT_RELEASE_CANDIDATE);
|
|
public readonly VersionDefinition IncreasePatch() => new(Major, Minor, Patch + 1, DEFAULT_RELEASE_CANDIDATE);
|
|
public readonly VersionDefinition IncreaseReleaseCandidate() => new(Major, Minor, Patch, ReleaseCandidate + 1);
|
|
public readonly VersionDefinition ToReleaseVersion() => new(Major, Minor, Patch, RELEASE_RC_VALUE);
|
|
|
|
public readonly uint BuildNumber => uint.Parse($"{Major:00}{Minor:00}{Patch:00}{ReleaseCandidate:00}");
|
|
|
|
public override readonly string ToString()
|
|
{
|
|
if (IsRelease)
|
|
return $"{Major}.{Minor}.{Patch}";
|
|
return $"{Major}.{Minor}.{Patch}-rc{ReleaseCandidate}";
|
|
}
|
|
|
|
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 static bool operator >=(VersionDefinition left, VersionDefinition right) => left.BuildNumber >= right.BuildNumber;
|
|
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 static bool operator !=(VersionDefinition left, VersionDefinition right) => left.BuildNumber != right.BuildNumber;
|
|
}
|
|
|
|
private static class GitProcess
|
|
{
|
|
public static VersionDefinition GetLatestBuildVersion() => new(GetLatestBuildVersionString());
|
|
public static VersionDefinition GetUpcomingReleaseVersion() => GetUpcomingReleaseCandidateVersion().ToReleaseVersion();
|
|
public static VersionDefinition GetUpcomingReleaseCandidateVersion()
|
|
{
|
|
VersionDefinition latestVersionDefinition = GetLatestBuildVersion();
|
|
string[] commits = GetCommitsSinceLastTag();
|
|
return ApplySemVer(latestVersionDefinition, commits);
|
|
}
|
|
|
|
public static VersionDefinition GetVersion(string version, IList<string> gitLogs)
|
|
=> ApplySemVer(new(version), gitLogs);
|
|
|
|
public static VersionDefinition ApplySemVer(VersionDefinition latestVersionDefinition, IList<string> commits)
|
|
{
|
|
VersionDefinition result = latestVersionDefinition.IsRelease ? latestVersionDefinition.IncreasePatch() : latestVersionDefinition;
|
|
for (int i = commits.Count - 1; i >= 0; i--)
|
|
{
|
|
string line = commits[i];
|
|
if (string.IsNullOrWhiteSpace(line))
|
|
continue;
|
|
|
|
string commitTitle = line.Length > 9 ? line[9..] : line;
|
|
if (commitTitle.StartsWith("breaking change", StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
result = result.IncreaseMajor();
|
|
break;
|
|
}
|
|
|
|
if (latestVersionDefinition.Minor != result.Minor)
|
|
continue;
|
|
|
|
if (commitTitle.StartsWith("feat", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
result = result.IncreaseMinor();
|
|
continue;
|
|
}
|
|
|
|
if (latestVersionDefinition.Patch != result.Patch)
|
|
continue;
|
|
|
|
if (commitTitle.StartsWith("fix", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
result = result.IncreasePatch();
|
|
continue;
|
|
}
|
|
|
|
if (latestVersionDefinition.ReleaseCandidate == result.ReleaseCandidate)
|
|
result = result.IncreaseReleaseCandidate();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static string GetLatestBuildVersionString()
|
|
=> RunGitCommand($"describe --tags --abbrev=0");
|
|
|
|
public static string[] GetCommits()
|
|
=> RunGitCommand("log --oneline").Replace("\r", "").Split('\n');
|
|
|
|
public static string[] GetCommitsSinceLastTag()
|
|
=> RunGitCommand($"log {GetLatestBuildVersionString()}..HEAD --oneline").Replace("\r", "").Split('\n');
|
|
|
|
public static string CreateVersionTag(VersionDefinition versionDefinition)
|
|
=> CreateTag($"v{versionDefinition.Version}", $"{(versionDefinition.IsRelease ? "Release" : "Build")} {versionDefinition.Version} with build number: {versionDefinition.BuildNumber}\"");
|
|
|
|
public static string Push()
|
|
=> RunGitCommand($"push");
|
|
|
|
public static string Add(IList<string> files)
|
|
=> RunGitCommand($"add \"{string.Join("\" \"", files)}\"");
|
|
|
|
public static string Add(string file)
|
|
=> RunGitCommand($"add \"{file}\"");
|
|
|
|
public static string Commit(string message)
|
|
=> RunGitCommand($"commit -m \"{message}\"");
|
|
|
|
public static string PushTags()
|
|
=> RunGitCommand($"tag --push");
|
|
|
|
public static string PushVersionTag(VersionDefinition versionDefinition)
|
|
=> RunGitCommand($"push origin tag v{versionDefinition.Version}");
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|