Editor/MyEditorMenu.cs
using Editor;
using Sandbox;
using Sandbox.Diagnostics;
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
interface IHasChanges
{
string Changes { get; set; }
}
public static class MyEditorMenu
{
private static readonly Logger Log = new( "Changelog Helper" );
static async Task<string> GetCurrentPublishedHash()
{
var pkg = await Package.Fetch( Game.Ident, false );
string hash = null;
// pkg.Revision is a Sandbox.PackageRevision or something like that which has the 'Changes' property we actually want
if ( pkg.Revision.GetSerialized().TryGetProperty( "Changes", out var prop ) )
{
hash = prop.GetValue<string>();
}
if ( !VerifyHash( hash ) )
hash = null;
return hash;
}
/// <summary>
/// Does it look like a hash?
/// </summary>
static bool VerifyHash( string hash )
{
return Regex.IsMatch( hash, @"^[a-z0-9]+$" );
}
/// <summary>
/// Does not verify arguments.
/// </summary>
static async Task<string> ExecuteGit( string arguments )
{
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "git",
Arguments = arguments,
WorkingDirectory = Project.Current.GetRootPath(),
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
proc.Start();
var output = proc.StandardOutput.ReadToEnd();
var errors = proc.StandardError.ReadToEnd();
await proc.WaitForExitAsync();
if ( !string.IsNullOrEmpty( errors ) )
{
Log.Error( errors );
}
return output;
}
static async Task<string> GetChangelog()
{
var hash = await GetCurrentPublishedHash();
if ( string.IsNullOrEmpty( hash ) )
{
throw new Exception( "Unable to get commit hash from previous publish" );
}
// this should already be filtered out by VerifyHash, but nothing wrong with more asserts :)
Assert.False( hash.Contains( '"' ) );
Assert.False( hash.Contains( ' ' ) );
var log = await ExecuteGit( $"log --reverse --format=%s {hash}..HEAD" );
if ( string.IsNullOrEmpty( log ) )
{
throw new Exception( "Generated changelog was empty!" );
}
return log;
}
static async Task<string> GetCurrentRevision()
{
var rev = await ExecuteGit( $"rev-parse HEAD" );
if ( string.IsNullOrEmpty( rev ) )
{
throw new Exception( "Something went wrong!" );
}
return rev[0..7];
}
[Menu( "Editor", "Changelog Helper/Copy info" )]
public static async void CopyInfo()
{
var changelog = "";
try
{
changelog = await GetChangelog();
}
catch
{
// It's fine if we don't have a changelog (like for initial commits)
}
var revision = "";
try
{
revision = await GetCurrentRevision();
}
catch ( Exception e )
{
// It's *not* fine if we can't find the current revision.
Log.Error( e );
EditorUtility.DisplayDialog( "Error", $"{e.Message} See Console output for more info." );
return;
}
if ( string.IsNullOrEmpty( changelog ) )
{
EditorUtility.Clipboard.Copy( revision );
Log.Warning( "Failed to get changelog, but the current revision was copied." );
}
else
{
EditorUtility.Clipboard.Copy( $"{revision}\n{changelog}" );
Log.Info( "Copied!" );
}
}
}