Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add release helper script #1540

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/internals/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ Releases are triggered manually, on Monday. Default release rotation is on the d
The middle name is the default release manager for the _current_ week. After the release, please
ping the next person to pass the baton.

Before triggering a release, update CHANGELOG.md with the changes since the last release. You can
use the following command to see all relevant merges:
Before triggering a release, update CHANGELOG.md with the changes since the last release. Run the
following command to create a release branch and generate changelog skeleton:

```console
$ git fetch origin && git log --merges origin/release..origin/main
$ ./zig/zig build scripts -- changelog
```

After the changelog PR is merged, trigger a release by pushing a commit from `origin/main` to
Expand Down
136 changes: 136 additions & 0 deletions src/scripts/changelog.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
const std = @import("std");
const assert = std.debug.assert;

const stdx = @import("../stdx.zig");
const Shell = @import("../shell.zig");

const log = std.log;

pub fn main(shell: *Shell, gpa: std.mem.Allocator) !void {
_ = gpa;

const today = try date_iso(shell);

try shell.exec("git fetch origin --quiet", .{});
try shell.exec("git switch --create release-{today} origin/main", .{ .today = today });

const merges = try shell.exec_stdout("git log --merges origin/release..origin/main", .{});
try shell.project_root.writeFile("./zig-cache/merges.txt", merges);
log.info("merged PRs: ./zig-cache/merges.txt", .{});

const max_bytes = 10 * 1024 * 1024;
const changelog_current = try shell.project_root.readFileAlloc(
shell.arena.allocator(),
"./CHANGELOG.md",
max_bytes,
);

var changelog_new = std.ArrayList(u8).init(shell.arena.allocator());
try format_changelog(changelog_new.writer(), .{
.changelog_current = changelog_current,
.merges = merges,
.today = today,
});

try shell.project_root.writeFile("CHANGELOG.md", changelog_new.items);

log.info("don't forget to update ./CHANGELOG.md", .{});
}

fn format_changelog(buffer: std.ArrayList(u8).Writer, options: struct {
changelog_current: []const u8,
merges: []const u8,
today: []const u8,
}) !void {
if (std.mem.indexOf(u8, options.changelog_current, options.today) != null) {
return error.ChangelogAlreadyUpdated;
}

try buffer.print(
\\# TigerBeetle Changelog
\\
\\## {s}
\\
\\
, .{options.today});

var merges_left = options.merges;
for (0..128) |_| {
const merge = try format_changelog_cut_single_merge(&merges_left) orelse break;

try buffer.print(
\\- [#{d}](https://github.com/tigerbeetle/tigerbeetle/pull/{d})
\\ {s}
\\
, .{ merge.pr, merge.pr, merge.summary });
} else @panic("suspiciously many PRs merged");
assert(std.mem.indexOf(u8, merges_left, "commit") == null);

try buffer.print(
\\
\\### Safety And Performance
\\
\\-
\\
\\### Features
\\
\\-
\\
\\### Internals
\\
\\-
\\
\\### TigerTracks 🎧
\\
\\- []()
\\
\\
, .{});

const changelog_rest = stdx.cut(
options.changelog_current,
"# TigerBeetle Changelog\n\n",
) orelse return error.ParseChangelog;

try buffer.writeAll(changelog_rest.suffix);
}

fn format_changelog_cut_single_merge(merges_left: *[]const u8) !?struct {
pr: u16,
summary: []const u8,
} {
errdefer {
log.err("failed to parse:\n{s}", .{merges_left.*});
}

// This is what we are parsing here:
//
// commit 02650cd67da855609cc41196e0d6f639b870ccf5
// Merge: b7c2fcda 4bb433ce
// Author: protty <[email protected]>
// Date: Fri Feb 9 18:37:04 2024 +0000
//
// Merge pull request #1523 from tigerbeetle/king/client-uid
//
// Client: add ULID helper functions

var cut = stdx.cut(merges_left.*, "Merge pull request #") orelse return null;
merges_left.* = cut.suffix;

cut = stdx.cut(merges_left.*, " from ") orelse return error.ParseMergeLog;
const pr = try std.fmt.parseInt(u16, cut.prefix, 10);
merges_left.* = cut.suffix;

cut = stdx.cut(merges_left.*, "\n \n ") orelse return error.ParseMergeLog;
merges_left.* = cut.suffix;

cut = stdx.cut(merges_left.*, "\n") orelse return error.ParseMergeLog;
const summary = cut.prefix;
merges_left.* = cut.suffix;

return .{ .pr = pr, .summary = summary };
}

fn date_iso(shell: *Shell) ![]const u8 {
return try shell.exec_stdout("date --iso", .{});
}
3 changes: 3 additions & 0 deletions src/scripts/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ const Shell = @import("../shell.zig");
const ci = @import("./ci.zig");
const release = @import("./release.zig");
const devhub = @import("./devhub.zig");
const changelog = @import("./changelog.zig");

const CliArgs = union(enum) {
ci: ci.CliArgs,
release: release.CliArgs,
devhub: devhub.CliArgs,
changelog: void,
};

pub fn main() !void {
Expand All @@ -50,5 +52,6 @@ pub fn main() !void {
.ci => |args_ci| try ci.main(shell, gpa, args_ci),
.release => |args_release| try release.main(shell, gpa, args_release),
.devhub => |args_devhub| try devhub.main(shell, gpa, args_devhub),
.changelog => try changelog.main(shell, gpa),
}
}
Loading