From 4ffd9a8d461190fae09ef485d818d964b27a1052 Mon Sep 17 00:00:00 2001 From: Jason McIntosh Date: Sun, 21 Jun 2026 20:01:05 -0400 Subject: [PATCH] Don't die when tags.tt is missing (#41) tags.tt is the one non-critical template, but publication died without it even for blogs that have no tags, because the tag *index* page was always rendered. Guard publish_tag_indexes: if tags.tt is absent, skip tag-page publication and carry on. Warn (rather than die) only when the blog actually uses tags and therefore loses content. Adds t/missing_tags_template.t covering both the tag-free case (publishes silently) and the tagged case (publishes with a warning). Co-Authored-By: Claude Opus 4.8 --- lib/Plerd.pm | 11 ++++++ t/missing_tags_template.t | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 t/missing_tags_template.t diff --git a/lib/Plerd.pm b/lib/Plerd.pm index eba0ec5..caa46b8 100644 --- a/lib/Plerd.pm +++ b/lib/Plerd.pm @@ -497,6 +497,17 @@ sub neighbor_basename { sub publish_tag_indexes { my $self = shift; + # tags.tt is the one non-critical template: if it's missing, publish the + # rest of the blog anyway rather than dying. Warn only if the blog actually + # uses tags and therefore loses content by skipping their pages. + unless ( -e $self->tags_template_file ) { + if ( $self->has_tags ) { + carp "This blog uses tags, but its template directory has no " + . "tags.tt file. Skipping publication of tag pages.\n"; + } + return; + } + my $tag_map = $self->tags_map; # Commentary: Ideally we'd just pass a sorted array of tag objects diff --git a/t/missing_tags_template.t b/t/missing_tags_template.t new file mode 100644 index 0000000..005fd87 --- /dev/null +++ b/t/missing_tags_template.t @@ -0,0 +1,76 @@ +use warnings; +use strict; +use Test::More; +use Test::Warn; +use Path::Class::Dir; +use Path::Class::File; +use URI; + +use FindBin; +use lib "$FindBin::Bin/../lib"; + +use_ok( 'Plerd' ); +use Plerd::Init; + +# Regression test for GitHub issue #41: tags.tt is the one non-critical +# template. If it's missing, the blog should still publish. It should publish +# silently when the blog has no tags, and warn (rather than die) when the blog +# does use tags but can't render their pages. + +sub fresh_blog { + my ( $name ) = @_; + my $blog_dir = Path::Class::Dir->new( "$FindBin::Bin/$name" ); + $blog_dir->rmtree; + Plerd::Init::initialize( $blog_dir->stringify, 0 ); + + # Remove the tags template to simulate a blog that lacks it. + Path::Class::File->new( $blog_dir, 'templates', 'tags.tt' )->remove; + + my $plerd = Plerd->new( + path => $blog_dir->stringify, + title => 'Test Blog', + author_name => 'Nobody', + author_email => 'nobody@example.com', + base_uri => URI->new( 'http://blog.example.com/' ), + ); + return ( $blog_dir, $plerd ); +} + +# Case 1: a blog with no tags at all. +{ + my ( $blog_dir, $plerd ) = fresh_blog( 'no_tags_blog' ); + my $source = Path::Class::File->new( $blog_dir, 'source', '2018-01-01-hello.md' ); + $source->spew( iomode => '>:encoding(utf8)', "title: Hello\n\nNo tags here.\n" ); + + warning_is { eval { $plerd->publish_all } } undef, + 'Publishing a tag-free blog without tags.tt produces no warning.'; + is( $@, '', 'Publishing a tag-free blog without tags.tt does not die.' ); + ok( + -e Path::Class::File->new( $blog_dir, 'docroot', '2018-01-01-hello.html' ), + 'The post still published.' + ); + + $blog_dir->rmtree; +} + +# Case 2: a blog that does use tags. +{ + my ( $blog_dir, $plerd ) = fresh_blog( 'tagged_blog' ); + my $source = Path::Class::File->new( $blog_dir, 'source', '2018-01-02-tagged.md' ); + $source->spew( + iomode => '>:encoding(utf8)', + "title: Tagged\ntags: foo, bar\n\nThis post has tags.\n" + ); + + warning_like { eval { $plerd->publish_all } } qr/tags\.tt/, + 'Publishing a tagged blog without tags.tt warns about the missing template.'; + is( $@, '', 'Publishing a tagged blog without tags.tt does not die.' ); + ok( + -e Path::Class::File->new( $blog_dir, 'docroot', '2018-01-02-tagged.html' ), + 'The post still published.' + ); + + $blog_dir->rmtree; +} + +done_testing();