Skip to content

Commit

Permalink
added add-releasenote command (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasduft committed Feb 17, 2024
1 parent 4c31ee2 commit 14d1f08
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 35 deletions.
12 changes: 12 additions & 0 deletions notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
TODO:


----------------------------------------------------------------------------------------------------
Links:

Release Notes
- how to write release Notes
- https://canny.io/blog/release-notes/
- https://www.appcues.com/blog/release-notes-examples
- sample templates
- https://gist.github.com/andreasonny83/24c733ae50cadf00fcf83bc8beaa8e6a
22 changes: 9 additions & 13 deletions src/releasy/Changelog/ChangelogCreator.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
using System.Text.Json;

namespace tomware.Releasy;
namespace tomware.Releasy.Changelog;

internal sealed class ChangelogCreator
{
private readonly ChangelogParam _changelogParam;
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
WriteIndented = true
};

public ChangelogCreator
(
ChangelogParam changelogParam
)
public ChangelogCreator(ChangelogParam changelogParam)
{
_changelogParam = changelogParam;
}
Expand All @@ -23,17 +25,11 @@ public void Create()
_changelogParam.Message
);

var content = JsonSerializer.Serialize(
changelog,
new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
WriteIndented = true
});

// Guid ToString(...) formats (https://learn.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=net-6.0)
var fileName = changelog.Id.ToString("N");
var path = $"{fileName}.{Constants.ChangelogEntryFileExtension}";

var content = JsonSerializer.Serialize(changelog, _jsonSerializerOptions);
File.WriteAllText(path, content);
}
}
2 changes: 1 addition & 1 deletion src/releasy/Changelog/ChangelogEntry.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace tomware.Releasy;
namespace tomware.Releasy.Changelog;

internal sealed class ChangelogEntry
{
Expand Down
2 changes: 1 addition & 1 deletion src/releasy/Changelog/ChangelogParam.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace tomware.Releasy;
namespace tomware.Releasy.Changelog;

internal sealed record ChangelogParam
(
Expand Down
2 changes: 1 addition & 1 deletion src/releasy/Changelog/ChangelogUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using Fluid;

using tomware.Releasy;
namespace tomware.Releasy.Changelog;

internal sealed class ChangelogUpdater
{
Expand Down
2 changes: 1 addition & 1 deletion src/releasy/Changelog/ChangelogUpdaterParam.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace tomware.Releasy;
namespace tomware.Releasy.Changelog;

internal sealed record ChangelogUpdaterParam
(
Expand Down
48 changes: 45 additions & 3 deletions src/releasy/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using McMaster.Extensions.CommandLineUtils;

using tomware.Releasy;
using tomware.Releasy.Changelog;
using tomware.Releasy.Releasenotes;

using static tomware.Releasy.ConsoleHelper;

Expand All @@ -26,13 +27,13 @@
: ReadInput("Enter your IssueId");
var prefix = prefixOption.HasValue()
? prefixOption.Value() ?? throw new InvalidOperationException(nameof(prefixOption.Value))
: ReadInput("Enter prefix (i.e. added, changed, deprecated, removed, fixed, security)");
: ReadInput("Enter prefix (i.e. added, changed, deprecated, fixed, removed, security)");
var tag = tagOption.HasValue()
? tagOption.Value() ?? throw new InvalidOperationException(nameof(tagOption.Value))
: ReadInput("Enter tag");
var message = messageOption.HasValue()
? messageOption.Value() ?? throw new InvalidOperationException(nameof(messageOption.Value))
: ReadInput("Enter message");
: ReadInput("Enter message (can contain simple inline markdown)");

var creator = new ChangelogCreator(
new ChangelogParam(
Expand All @@ -47,6 +48,47 @@
});
});

app.Command("add-releasenote", (command) =>
{
command.Description = "Creates a new release note entry (i.e. releasy add-releasenote -i \"my-issue-id\" -p \"feature\" -t \"audit\" -m \"My super duper text\")";
var issueIdOption = command.Option("-i|--issue-id", "IssueId to link to your ticketing system", CommandOptionType.SingleValue);
var prefixOption = command.Option("-p|--prefix", "Prefix like breaking, deprecated, feature, fix, performance, removed, security, upgrade", CommandOptionType.SingleValue);
var tagOption = command.Option("-t|--tag", "Tag that specifies the changelog entry (i.e. audit). Helpful for grouping and such things.", CommandOptionType.SingleValue);
var messageOption = command.Option("-m|--message", "Release note text.", CommandOptionType.SingleValue);
var instructionsOption = command.Option("-ins|--instructions", "Optional instructions for the release note message.", CommandOptionType.SingleValue);
command.HelpOption();
command.OnExecute(() =>
{
var issueId = issueIdOption.HasValue()
? issueIdOption.Value() ?? throw new InvalidOperationException(nameof(issueIdOption.Value))
: ReadInput("Enter your IssueId");
var prefix = prefixOption.HasValue()
? prefixOption.Value() ?? throw new InvalidOperationException(nameof(prefixOption.Value))
: ReadInput("Enter prefix (i.e. breaking, deprecated, feature, fix, performance, removed, security, upgrade)");
var tag = tagOption.HasValue()
? tagOption.Value() ?? throw new InvalidOperationException(nameof(tagOption.Value))
: ReadInput("Enter tag");
var message = messageOption.HasValue()
? messageOption.Value() ?? throw new InvalidOperationException(nameof(messageOption.Value))
: ReadInput("Enter release note message (can contain simple inline markdown)");
var instructions = instructionsOption.HasValue()
? [instructionsOption.Value() ?? throw new InvalidOperationException(nameof(instructionsOption.Value))]
: ReadMultilineInput("Enter intstructions for the release note message (can contain simple inline markdown)");

var creator = new ReleaseNoteCreator(
new ReleaseNoteParam(
issueId,
prefix,
tag,
message,
instructions
));
creator.Create();

return 0;
});
});

app.Command("create-releasenotes", (command) =>
{
command.Description = "Creates releasenotes based on changelog entries for a dedicated release (i.e. releasy create-releasenotes -v \"1.2.3\" -p \"some-perma-link\")";
Expand Down
36 changes: 36 additions & 0 deletions src/releasy/Releasenotes/ReleaseNoteCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Text.Json;

namespace tomware.Releasy.Releasenotes;

internal sealed class ReleaseNoteCreator
{
private readonly ReleaseNoteParam _releaseNoteParam;
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
PropertyNameCaseInsensitive = true,
WriteIndented = true
};

public ReleaseNoteCreator(ReleaseNoteParam changelogParam)
{
_releaseNoteParam = changelogParam;
}

public void Create()
{
var releaseNoteEntry = ReleaseNoteEntry.Create(
_releaseNoteParam.IssueId,
_releaseNoteParam.Prefix,
_releaseNoteParam.Tag,
_releaseNoteParam.Message,
_releaseNoteParam.Instructions
);

// Guid ToString(...) formats (https://learn.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=net-6.0)
var fileName = releaseNoteEntry.Id.ToString("N");
var path = $"{fileName}.{Constants.ReleaseNoteEntryFileExtension}";

var content = JsonSerializer.Serialize(releaseNoteEntry, _jsonSerializerOptions);
File.WriteAllText(path, content);
}
}
31 changes: 31 additions & 0 deletions src/releasy/Releasenotes/ReleaseNoteEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace tomware.Releasy.Releasenotes;

internal sealed class ReleaseNoteEntry
{
public Guid Id { get; set; } = Guid.NewGuid();
public string IssueId { get; set; } = string.Empty;
public string Prefix { get; set; } = string.Empty;
public string Tag { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
public string[] Instructions { get; set; } = [];
public DateTime CreatedAt { get; set; } = DateTime.Now;
public string CreatedBy { get; set; } = Environment.UserName;

public static ReleaseNoteEntry Create(
string issueId,
string prefix,
string tag,
string message,
string[] instructions
)
{
return new ReleaseNoteEntry
{
IssueId = issueId,
Prefix = prefix.UpperCaseFirstLetter(),
Tag = tag,
Message = message,
Instructions = instructions
};
}
}
10 changes: 10 additions & 0 deletions src/releasy/Releasenotes/ReleaseNoteParam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace tomware.Releasy.Releasenotes;

internal sealed record ReleaseNoteParam
(
string IssueId,
string Prefix,
string Tag,
string Message,
string[] Instructions
);
28 changes: 14 additions & 14 deletions src/releasy/Releasenotes/ReleaseNotes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@

using Fluid;

namespace tomware.Releasy;
namespace tomware.Releasy.Releasenotes;

internal sealed class ReleaseNotes
{
private readonly List<ChangelogEntry> _releaseNotes;
private readonly List<ReleaseNoteEntry> _releaseNotes;
private readonly ReleaseNotesParam _releaseNotesParam;

public ReleaseNotes(
ReleaseNotesParam releaseNotesParam
)
public ReleaseNotes(ReleaseNotesParam releaseNotesParam)
{
_releaseNotes = new List<ChangelogEntry>();
_releaseNotes = [];
_releaseNotesParam = releaseNotesParam;
}

Expand All @@ -24,7 +22,7 @@ public void Create()
foreach (var file in files)
{
var content = File.ReadAllText(file);
var note = JsonSerializer.Deserialize<ChangelogEntry>(content);
var note = JsonSerializer.Deserialize<ReleaseNoteEntry>(content);
if (note != null)
_releaseNotes.Add(note);
}
Expand Down Expand Up @@ -64,42 +62,44 @@ public void Create()
}
}

private static IEnumerable<string> GetFiles(string inputDirectory)
private static List<string> GetFiles(string inputDirectory)
{
var files = new List<string>();

files.AddRange(Directory.GetFiles(
inputDirectory,
$"*.{Constants.ChangelogEntryFileExtension}",
$"*.{Constants.ReleaseNoteEntryFileExtension}",
SearchOption.AllDirectories
));

return files;
}

private static IEnumerable<Prefix> BuildPrefixes(IEnumerable<ChangelogEntry> releaseNotes)
private static IEnumerable<Prefix> BuildPrefixes(IEnumerable<ReleaseNoteEntry> releaseNotes)
{
var prefixes = new List<Prefix>();

var prefixGroups = releaseNotes.Select(r => r.Prefix).Distinct();
foreach (var prefix in prefixGroups)
{
var notes = releaseNotes.Where(r => r.Prefix == prefix).OrderBy(r => r.CreatedAt);
var notes = releaseNotes
.Where(r => r.Prefix == prefix)
.OrderBy(r => r.CreatedAt);

prefixes.Add(new Prefix(prefix, notes));
}

return prefixes.OrderBy(p => p.Name);
}

public static void SaveFile(string output, object model)
private static void SaveFile(string output, object model)
{
var source = TemplateLoader.GetResource(Templates.ReleaseNotes);
var template = new FluidParser().Parse(source);

var options = new TemplateOptions();
options.MemberAccessStrategy.Register<Prefix>();
options.MemberAccessStrategy.Register<ChangelogEntry>();
options.MemberAccessStrategy.Register<ReleaseNoteEntry>();

var content = template.Render(new TemplateContext(model, options));
File.WriteAllText(output, content);
Expand All @@ -108,6 +108,6 @@ public static void SaveFile(string output, object model)
private sealed record Prefix
(
string Name,
IEnumerable<ChangelogEntry> Entries
IEnumerable<ReleaseNoteEntry> Entries
);
}
2 changes: 1 addition & 1 deletion src/releasy/Releasenotes/ReleaseNotesParam.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace tomware.Releasy;
namespace tomware.Releasy.Releasenotes;

internal sealed record ReleaseNotesParam
(
Expand Down
15 changes: 15 additions & 0 deletions src/releasy/Utils/ConsoleHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ public static string ReadInput(string prompt)
: string.Empty;
}

public static string[] ReadMultilineInput(string prompt)
{
WriteYellow($"{prompt}: " + Environment.NewLine);

var lines = new List<string>();

string? line;
while (!string.IsNullOrWhiteSpace(line = Console.ReadLine()))
{
lines.Add(line + Environment.NewLine);
}

return lines.ToArray();
}

public static string ReadPassword()
{
WriteYellow("Please enter a password: ");
Expand Down
1 change: 1 addition & 0 deletions src/releasy/Utils/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ namespace tomware.Releasy;
public static class Constants
{
public const string ChangelogEntryFileExtension = "cle";
public const string ReleaseNoteEntryFileExtension = "rne";
}

0 comments on commit 14d1f08

Please sign in to comment.