DEV: Improve rake `release_note:generate` date handling (#13726)

DEV: Improve rake release_note:generate date handling (#13726)

  • DEV: Improve rake release_note:generate date handling

A commit-ish value like HEAD@{2021-01-01} is based on the local state of HEAD on that date. It does not use dates attached to commits.

Instead, the rake task now detects date-like strings and supplies them to git log via the --after and --before flags

  • Skip printing plugin when there are no changes found

A list of skipped plugins is printed on a single line at the end of the output

diff --git a/lib/tasks/release_note.rake b/lib/tasks/release_note.rake
index cf19078..12d68c1 100644
--- a/lib/tasks/release_note.rake
+++ b/lib/tasks/release_note.rake
@@ -1,48 +1,26 @@
 # frozen_string_literal: true
 
+DATE_REGEX = /\A\d{4}-\d{2}-\d{2}/
+
+CHANGE_TYPES = [
+  { pattern: /^FEATURE:/, heading: "New Features" },
+  { pattern: /^FIX:/, heading: "Bug Fixes" },
+  { pattern: /^UX:/, heading: "UX Changes" },
+  { pattern: /^SECURITY:/, heading: "Security Changes" },
+  { pattern: /^PERF:/, heading: "Performance" },
+  { pattern: /^A11Y:/, heading: "Accessibility" },
+]
+
 desc "generate a release note from the important commits"
 task "release_note:generate", :from, :to, :repo do |t, args|
   repo = args[:repo] || "."
-  from = args[:from] || `git -C #{repo} describe --tags --abbrev=0`.strip
-  to = args[:to] || "HEAD"
-
-  bug_fixes = Set.new
-  new_features = Set.new
-  ux_changes = Set.new
-  sec_changes = Set.new
-  perf_changes = Set.new
-  a11y_changes = Set.new
-
-  out = `git -C #{repo} log --pretty="tformat:%s" '#{from}..#{to}'`
-  next "Status #{$?.exitstatus} running git log\n#{out}" if !$?.success?
+  changes = find_changes(repo, args[:from], args[:to])
 
-  out.each_line do |comment|
-    next if comment =~ /^\s*Revert/
-    split_comments(comment).each do |line|
-      if line =~ /^FIX:/
-        bug_fixes << better(line)
-      elsif line =~ /^FEATURE:/
-        new_features << better(line)
-      elsif line =~ /^UX:/
-        ux_changes << better(line)
-      elsif line =~ /^SECURITY:/
-        sec_changes << better(line)
-      elsif line =~ /^PERF:/
-        perf_changes << better(line)
-      elsif line =~ /^A11Y:/
-        a11y_changes << better(line)
-      end
-    end
+  CHANGE_TYPES.each do |ct|
+    print_changes(ct[:heading], changes[ct])
   end
 
-  print_changes("New Features", new_features)
-  print_changes("Bug Fixes", bug_fixes)
-  print_changes("UX Changes", ux_changes)
-  print_changes("Security Changes", sec_changes)
-  print_changes("Performance", perf_changes)
-  print_changes("Accessibility", a11y_changes)
-
-  if [bug_fixes, new_features, ux_changes, sec_changes, perf_changes, a11y_changes].all?(&:empty?)
+  if changes.values.all?(&:empty?)
     puts "(no changes)", ""
   end
 end
@@ -51,7 +29,7 @@ end
 #  1. Make sure you have a local, up-to-date clone of https://github.com/discourse/all-the-plugins
 #  2. In all-the-plugins, `git submodule update --init --recursive --remote`
 #  3. Change back to your discourse directory
-#  4. rake "release_note:plugins:generate[ HEAD@{2021-06-01} , HEAD@{now} , /path/to/all-the-plugins/plugins/* , discourse ]"
+#  4. rake "release_note:plugins:generate[ 2021-06-01 , 2021-07-01 , /path/to/all-the-plugins/plugins/* , discourse ]"
 desc "generate release notes for all official plugins in a directory"
 task "release_note:plugins:generate", :from, :to, :plugin_glob, :org do |t, args|
   from = args[:from]
@@ -65,12 +43,60 @@ task "release_note:plugins:generate", :from, :to, :plugin_glob, :org do |t, args
     all_repos = all_repos.filter { |dir| `git -C #{dir} remote get-url origin`.match?(/github.com[\/:]#{git_org}\//) }
   end
 
+  no_changes_repos = []
+
   all_repos.each do |dir|
-    puts "## #{File.basename(dir)}\n\n"
-    Rake::Task["release_note:generate"].invoke(from, to, dir)
-    Rake::Task["release_note:generate"].reenable
+    name = File.basename(dir)
+    changes = find_changes(dir, from, to)
+
+    if changes.values.all?(&:empty?)
+      no_changes_repos << name
+      next
+    end
+
+    puts "## #{name}\n\n"
+    CHANGE_TYPES.each do |ct|
+      print_changes(ct[:heading], changes[ct])
+    end
     puts "---", ""
   end
+
+  puts "(No changes found in #{no_changes_repos.join(", ")})"
+end
+
+def find_changes(repo, from, to)
+  dates = from&.match?(DATE_REGEX) || to&.match?(DATE_REGEX)
+
+  if !dates
+    from ||= `git -C #{repo} describe --tags --abbrev=0`.strip
+    to ||= "HEAD"
+  end
+
+  cmd = "git -C #{repo} log --pretty='tformat:%s' "
+  if dates
+    cmd += "--after '#{from}' " if from
+    cmd += "--before '#{to}' " if to
+  else
+    cmd += "#{from}..#{to}"
+  end
+
+  out = `#{cmd}`
+  raise "Status #{$?.exitstatus} running git log\n#{out}" if !$?.success?
+
+  changes = {}
+  CHANGE_TYPES.each do |ct|
+    changes[ct] = Set.new
+  end
+
+  out.each_line do |comment|
+    next if comment =~ /^\s*Revert/
+    split_comments(comment).each do |line|
+      ct = CHANGE_TYPES.find { |t| line =~ t[:pattern] }
+      changes[ct] << better(line) if ct
+    end
+  end
+
+  changes
 end
 
 def print_changes(heading, changes)

GitHub sha: 4ce58fbf0b3eb87387e63b29f8f0355f55da4087

This commit appears in #13726 which was approved by jomaxro. It was merged by SamSaffron.