Skip to content

Commit 34b4d88

Browse files
committed
Support user-driven templates
1 parent 377d8b9 commit 34b4d88

File tree

8 files changed

+115
-33
lines changed

8 files changed

+115
-33
lines changed

.tool-versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
zig 0.14.0
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 00003 - Support Templates Folder
2+
3+
## Abstract
4+
5+
Being able to provide your own templates for the README and the ADRs
6+
can be really useful. It allows you to customize this to your personal
7+
or team needs while still sticking with the tool and processes for
8+
maintaining proper ADRs.
9+
10+
## Context and Problem Statement
11+
12+
Currently, there is no way to deviate from the existing templates for
13+
the README and the ADRs. If you want to customize these, you will lose all
14+
changes upon regen of the README. Effectively, if you do not agree with
15+
the templates that are shipped with ADL, the tool may not be useful to you.
16+
17+
## Considered Options
18+
19+
### Do Nothing
20+
These templates are minimal and other additions can be captured elsewhere.
21+
22+
### Support user-driven templates
23+
Create a templates directory and allow users to specify templates to be
24+
used on behalf of the CLI when generated READMEs and ADRs. Specify the fields
25+
via a templating language that the CLI can replace.
26+
27+
## Decision Outcome
28+
29+
We are going to support user-driven templates via a templates folder in the ADR directory. The templates folder should not be linked in the README contents.
30+
The templates folder will also have it's own README with information on the
31+
supported files that you can template, as well as the templating items that
32+
can be replaced by the CLI such as timestamp or contents.
33+
34+
<!-- Add additional information here, comparison of options, research, etc -->

adr/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ This directory captures architecture decision records for this project.
44
An architecture decision record is a justified software design choice
55
that addresses a functional or non-functional requirement of architectural significance.
66

7-
This directory and README is managed by adl. Please use \`adl create\` to create a new ADR.
7+
This directory and README is managed by [adl](https://github.com/bradcypert/adl). Please use \`adl create\` to create a new ADR.
88
If you need to regenerate this readme without creating a new ADR, please use \`adl regen\`.
99

1010
## Contents
1111

1212
- [00000-Use-Deno.md](./00000-Use-Deno.md)
1313
- [00001-Support-an-assets-folder.md](./00001-Support-an-assets-folder.md)
1414
- [00002-Migrate-to-Zig.md](./00002-Migrate-to-Zig.md)
15+
- [00003-Support-Templates-Folder.md](./00003-Support-Templates-Folder.md)
1516

16-
Last generated Wed, 1 Jan 2025 21:48:03 UTC
17+
Last generated Fri, 23 May 2025 18:56:25 UTC

adr/templates/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Templates and the Template Folder
2+
3+
The templates contained in this template folder will be used
4+
if they are defined. If they are not defined, we will default
5+
to the embedded templates used by the CLI.
6+
7+
This gives you the ability to customize your ADRs and READMEs
8+
to meet your personal or team needs.
9+
10+
## Supported Template Filenames
11+
12+
### template_readme.md
13+
This template is used to generate the README in the ADR folder.
14+
It supports the following items.
15+
16+
| Field | Purpose |
17+
|-----------------------|--------------------------------------------------------------------------------|
18+
| {{timestamp}} | The timestamp at which the README was last generated|
19+
| {{contents}} | The contents of the ADR folder, structured as an ordered list, sorted by name. |
20+
21+
### template_adr.md
22+
This template is used to generate a specific ADR.
23+
It supports the following items:
24+
25+
| Field | Purpose|
26+
|-----------------------|-------------------------------|
27+
| {{name}} | The name of the generated ADR |
28+

deno.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

deno.lock

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/main.zig

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,28 @@ const Datetime = @import("zig-datetime");
33
const readmeContents = @embedFile("./templates/readme_template.md");
44
const adrContents = @embedFile("./templates/adr_template.md");
55
const helpContents = @embedFile("./templates/help.txt");
6+
const templateReadmeContents = @embedFile("./templates/readme_templates_folder.md");
67

78
fn compareStrings(_: void, lhs: []const u8, rhs: []const u8) bool {
89
return std.mem.order(u8, lhs, rhs).compare(std.math.CompareOperator.lt);
910
}
1011

11-
fn rebuildReadme(allocator: std.mem.Allocator) !void {
12+
fn readFileIfExists(allocator: std.mem.Allocator, filepath: []const u8) ![]u8 {
13+
const templateFile = try std.fs.cwd().openFile(filepath, .{});
14+
defer templateFile.close();
15+
16+
const fileContents = try templateFile.readToEndAlloc(allocator, std.math.maxInt(usize));
17+
return fileContents;
18+
}
1219

20+
fn rebuildReadme(allocator: std.mem.Allocator) !void {
21+
const templateContents = readFileIfExists(allocator, "./adr/templates/template_readme.md") catch readmeContents;
1322
// TODO: Too many "Datetime"s
1423
const now = Datetime.datetime.Datetime.now();
1524
const date = try now.formatHttp(allocator);
1625
defer allocator.free(date);
1726

18-
const output = std.mem.replaceOwned(u8, allocator, readmeContents, "{{timestamp}}", date) catch @panic("out of memory");
27+
const output = std.mem.replaceOwned(u8, allocator, templateContents, "{{timestamp}}", date) catch @panic("out of memory");
1928
defer allocator.free(output);
2029

2130
const files = try getAllFilesInADRDir(allocator);
@@ -65,17 +74,22 @@ fn generateADR(allocator: std.mem.Allocator, n: u64, name: []u8) !void {
6574
);
6675
defer allocator.free(heading);
6776

68-
const contents = std.mem.replaceOwned(u8, allocator, adrContents, "{{name}}", heading) catch @panic("Out of memory");
77+
const templateContents = readFileIfExists(allocator, "./adr/templates/template_adr.md") catch adrContents;
78+
const contents = std.mem.replaceOwned(u8, allocator, templateContents, "{{name}}", heading) catch @panic("Out of memory");
6979
defer allocator.free(contents);
7080

7181
const f = try std.fs.cwd().createFile(fileName, .{ .read = true });
7282
defer f.close();
7383
try f.writeAll(contents);
7484
}
7585

76-
fn ensureDirsExist() !void {
86+
fn establishCoreFiles() !void {
7787
const cwd = std.fs.cwd();
7888
try cwd.makePath("./adr/assets");
89+
try cwd.makePath("./adr/templates");
90+
91+
const f = try std.fs.cwd().createFile("./adr/templates/README.md", .{});
92+
try f.writeAll(templateReadmeContents);
7993
}
8094

8195
fn getAllFilesInADRDir(allocator: std.mem.Allocator) !std.ArrayList([]const u8) {
@@ -89,7 +103,7 @@ fn getAllFilesInADRDir(allocator: std.mem.Allocator) !std.ArrayList([]const u8)
89103
var dirIterator = dir.iterate();
90104
while (try dirIterator.next()) |dirContent| {
91105
// Append the file name to the ArrayList
92-
if (!std.mem.eql(u8, dirContent.name, "README.md") and !std.mem.eql(u8, dirContent.name, "assets")) {
106+
if (!std.mem.eql(u8, dirContent.name, "README.md") and !std.mem.eql(u8, dirContent.name, "assets") and !std.mem.eql(u8, dirContent.name, "templates")) {
93107
const fileName = try allocator.dupe(u8, dirContent.name);
94108
try file_list.append(fileName);
95109
}
@@ -111,7 +125,7 @@ pub fn main() !void {
111125

112126
const action = if (args.len > 1) args[1] else "";
113127
if (std.mem.eql(u8, action, "create")) {
114-
try ensureDirsExist();
128+
try establishCoreFiles();
115129
const name = std.mem.join(allocator, " ", args[2..]) catch unreachable;
116130
if (name.len == 0) {
117131
_ = try stderr_file.write("No name supplied for the ADR. Command should be: adl create Name of ADR here\n");
@@ -123,7 +137,7 @@ pub fn main() !void {
123137
}
124138
allocator.free(name);
125139
} else if (std.mem.eql(u8, action, "regen")) {
126-
try ensureDirsExist();
140+
try establishCoreFiles();
127141
try rebuildReadme(allocator);
128142
} else {
129143
_ = bw.write(helpContents) catch @panic("Unable to write help contents");
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Templates and the Template Folder
2+
3+
The templates contained in this template folder will be used
4+
if they are defined. If they are not defined, we will default
5+
to the embedded templates used by the CLI.
6+
7+
This gives you the ability to customize your ADRs and READMEs
8+
to meet your personal or team needs.
9+
10+
## Supported Template Filenames
11+
12+
### template_readme.md
13+
This template is used to generate the README in the ADR folder.
14+
It supports the following items.
15+
16+
| Field | Purpose |
17+
|-----------------------|--------------------------------------------------------------------------------|
18+
| {{timestamp}} | The timestamp at which the README was last generated|
19+
| {{contents}} | The contents of the ADR folder, structured as an ordered list, sorted by name. |
20+
21+
### template_adr.md
22+
This template is used to generate a specific ADR.
23+
It supports the following items:
24+
25+
| Field | Purpose|
26+
|-----------------------|-------------------------------|
27+
| {{name}} | The name of the generated ADR |
28+

0 commit comments

Comments
 (0)