From 0abd960fc95c67db30707c2c056d6407f7a25562 Mon Sep 17 00:00:00 2001 From: Thomas Sader Date: Mon, 27 Mar 2017 01:41:14 +0200 Subject: [PATCH] Unify changelog generation. (cherry picked from commit 4b9c30a9bb988cbc436a9bad705dcbeb6120dafc) --- misc/genChangelog | 54 --------- misc/genchanges | 292 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 261 insertions(+), 85 deletions(-) delete mode 100755 misc/genChangelog diff --git a/misc/genChangelog b/misc/genChangelog deleted file mode 100755 index b44fff639..000000000 --- a/misc/genChangelog +++ /dev/null @@ -1,54 +0,0 @@ -#! /bin/sh -# -# genChangelog - Create a Changelog file based on git commits -# -# Copyright (C) 2004 - 2017 Eggheads Development Team -# -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -git log --no-merges --pretty=format:"%w(75)%H %n Committed %ai by %aN %n %s %n %b" $1 - -show_usage() { - echo "Usage: `basename $0` " - echo "" - exit 1 -} - - - -if test "x${1}" = "x-h" || test "x${1}" = "x--help"; then - show_usage -fi - -do_rc=0 -if test "x${1}" = "x-r" || test "x${1}" = "x--rc"; then - do_rc=1 - if test "x${2}" = "x"; then - show_usage - fi - rc_number=$2 -fi - -if test ! -f src/main.c; then - echo "You are not in the Eggdrop root directory." - exit 1 -fi - diff --git a/misc/genchanges b/misc/genchanges index 02ab95d12..15e4572f2 100755 --- a/misc/genchanges +++ b/misc/genchanges @@ -1,6 +1,6 @@ #! /usr/bin/env tclsh # -# genchanges - Generate changes summary for doc/Changes files. +# genchanges - Generate changelog (doc/Changes and ChangeLog) files. # # Copyright (C) 2017 Eggheads Development Team # @@ -22,48 +22,278 @@ # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. -package require Tcl 8.5 -proc show_usage {} { - puts "Syntax: $::argv0 \[show changes to this git tag (e.g. v1.8.1)\]" - puts "normal usage: \"$::argv0 v1.8.0\", then paste the result into doc/Changes1.8" - exit 1 +package require Tcl 8.6 +package require textutil::adjust + +proc get_usage {} { + return [subst [join { + {Syntax: $::argv0 \[options\] } {} {Commands:} + {short - Generate short changelog (doc/ChangesX.Y)} + {full - Generate full changelog (ChangeLog)} + {release - OVERWRITE ChangeLog and doc/ChangesX.Y} + {} {Options (general):} + {-d - Verbose debug logging} + {-r - Specify remote for tags and public branches} + {} {Options (short):} + {-e - Specify ref to exclude with ancestors} + {-i - Specify ref to include with ancestors} + {-n - Specify the upcoming version} + {} {Examples:} + { Generate doc/Changes1.8 for v1.8.2rc3:} + { $::argv0 -e v1.6.21 -i v1.8.1 -i v1.8.2 -i stable/1.8 -n 1.8.2rc3 short} + { Generate doc/Changes1.8 for v1.8.3 final (make sure version order is correct at the end):} + { $::argv0 -e v1.6.21 -i "v1.8.*" -i stable/1.8 -n 1.8.3 short} + { Generate ChangeLog for v1.8.3 final:} + { $::argv0 -i stable/1.8} + } \n]] } -if {[llength $argv] != 1 || [set basecommit [lindex $argv 0]] in {-h --help}} { - show_usage +proc commands {} { + lmap cmd [info commands cmd:*] { + string range $cmd 4 end + } } -if {[catch {exec git rev-list $basecommit..HEAD} commits]} { - puts "Error: git rev-list $basecommit..HEAD returned\n$commits\n" +proc fatal {msg {showusage 0}} { + if {$msg ne ""} { + puts stderr $msg + if {$showusage} { + puts stderr "" + } + } + if {$showusage} { + puts stderr [get_usage] + } exit 1 } -set result "" -foreach commit [lreverse $commits] { - set fullmsg [exec git show -s --pretty=format:%B $commit] - set shortmsg [exec git show -s --pretty=format:%s $commit] - set date [clock format [exec git show -s --pretty=format:%ct $commit] -gmt 1 -format "%Y-%m-%d"] - set found "" - set patch "" - foreach {- category names} [regexp -nocase -all -inline -- {(found|patch) by:([^\r\n/]+)} $fullmsg] { - foreach nick [split $names {, }] { - set nick [string trim $nick ""] - if {$nick ne ""} { - dict set [string tolower $category] $nick 1 +proc pop {listVar} { + upvar 1 $listVar list + set e [lindex $list 0] + set list [lrange $list 1 end] + return $e +} + +proc log {text} { + puts stderr $text +} + +proc vlog {text} { + if {$::verbose} { + log $text + } +} + +proc parsecmdline {argv} { + global verbose + if {![llength $argv]} { + fatal "" 1 + } + foreach var {remote command version includes excludes} { + set $var "" + } + set verbose 0 + while {[llength $argv]} { + set arg [pop argv] + if {[string index $arg 0] eq "-"} { + for {set i 1} {$i < [string length $arg]} {incr i} { + set c [string index $arg $i] + switch -exact -- $c { + "r" { set remote [pop argv] } + "d" { set verbose 1 } + "v" { set version [pop argv] } + "i" { lappend includes [pop argv] } + "e" { lappend excludes [pop argv] } + default { + fatal "Unknown option: -$c" 1 + } + } + vlog "OptParse: $c (left: $argv)" } + } else { + set command $arg + break } } - set secondline "" - if {[dict size $found]} { - lappend secondline "Found by: [join [dict keys $found] {, }]" + if {$command eq ""} { + fatal "No command specified." 1 + show_usage } - if {[dict size $patch]} { - lappend secondline "Patch by: [join [dict keys $patch] {, }]" + if {![llength $includes]} { + fatal "No -i includes specified." 1 } - if {[llength $secondline]} { - append shortmsg "\n [string repeat " " 10] [join $secondline { / }]" + foreach var {remote version includes excludes} { + cfg$var [set $var] } - lappend result " $date $shortmsg" + return $command } -puts [join [lreverse $result] \n\n] + +interp alias {} cfgincludes {} cfgtags includes +interp alias {} cfgexcludes {} cfgtags excludes + +proc cfgtags {varName patterns} { + global remote + upvar #0 $varName tags + set tags "" + foreach pattern $patterns { + set tmp [regexp -all -inline -- {\S+} [exec git tag -l $pattern]] + if {![llength $tmp]} { + # no matching tags + if {[catch {exec git rev-parse --verify -q $remote/$pattern}]} { + fatal "Could not parse revision $pattern on remote $remote." + } + set tmp [list $remote/$pattern] + } + lappend tags {*}$tmp + } +} + +proc cfgversion {version} { + if {$version ne "" && ![regexp {^\d+\.\d+\.\d+} $version]} { + fatal "Invalid ersion number: $version. Try 1.8.1 or similar." + } + set ::version $version +} + +proc cfgremote {remote} { + set remotes [regexp -all -inline -- {\S+} [exec git remote]] + if {![llength $remotes]} { + fatal "No git remotes configured." + exit 1 + } + if {$remote eq ""} { + if {[llength $remotes] == 1} { + set remote [lindex $remotes 0] + } else { + fatal "Multiple remotes available, must specify -r. Available: [join $remotes {, }]" + } + } + if {[llength $remotes] == 1 && $remote eq ""} { + set remote [lindex $remotes 0] + } + if {$remote ni $remotes} { + fatal "Unknown remote: $remote. Available: [join $remotes {, }]" + exit 1 + } + vlog "Remotes: '[join $remotes ',']'. Using '$remote'" + set ::remote $remote +} + +proc start {} { + global remote + set command [parsecmdline $::argv] + if {$command ni [commands]} { + fatal "Unknown command: $command. Available: [join [commands] {, }]" 1 + } + log "Working with remote $remote..." + cmd:$command +} + +proc revlist {} { + global includes excludes + set includestr $includes + set excludestr [lmap x $excludes { return -level 0 ^$x }] + return [list {*}$includestr {*}$excludestr] +} + +proc doexec {cmd} { + log "Executing: [join $cmd]" + if {[catch {exec {*}$cmd} res]} { + fatal "Error during executing: $res" + } + set res [regsub -all -- {\n\n\n+} [string trim $res] "\n\n"] + log "Executed: [join $cmd]" + return $res +} + +proc cmd:full {} { + set revlist [revlist] + set cmd [list git log --no-merges --date-order --name-status {--pretty=format:%n------------------------------%nCommit %h (%ai) by %aN %n%n%B%n%n} {*}[revlist]] + puts [doexec $cmd] +} + +proc cmd:short {} { + global version includes excludes + if {$version eq ""} { + fatal "Need version number (-v) for short changelog." + } + set cmd [list git rev-list --no-merges --reverse --author-date-order {*}[revlist]] + set commits [doexec $cmd] + set taglist [regexp -all -inline -- {\S+} [exec git tag --list]] + set tags "" + foreach tag $taglist { + dict set tags [string trim [exec git rev-parse $tag]] $tag + } + set lastdate "" + set lastappend "" + foreach commit $commits { + set fullmsg [exec git show -s --pretty=format:%B $commit] + set shortmsg [exec git show -s --pretty=format:%s $commit] + set date [clock format [exec git show -s --pretty=format:%ct $commit] -gmt 1 -format "%Y-%m-%d"] + set found "" + set patch "" + set shortmsg [string trim $shortmsg "- "] + if {$lastappend ne ""} { + lappend result {*}[string map [list %%CHANGELOGDATE%% [expr {($date eq $lastdate && !$forcedate) ? "[string repeat " " 10]" : "$lastdate"}]] $lastappend] + } + set forcedate 0 + foreach {- category names} [regexp -nocase -all -inline -- {(found|patch) by:([^\r\n/]+)} $fullmsg] { + foreach nick [split $names {, }] { + set nick [string trim $nick ""] + if {$nick ne ""} { + dict set [string tolower $category] $nick 1 + } + } + } + set shortmsgs "" + #ugly specific fixup + if {[string index $shortmsg 0] eq "*"} { + set split [split $shortmsg *] + foreach e $split { + set e [string trim $e] + if {$e eq ""} { continue } + lappend shortmsgs $e + } + } else { + set shortmsgs [list $shortmsg] + } + set secondline "" + if {[dict size $found]} { + lappend secondline "Found by: [join [dict keys $found] {, }]" + } + if {[dict size $patch]} { + lappend secondline "Patch by: [join [dict keys $patch] {, }]" + } + if {[llength $secondline]} { + set lastmsg [lindex $shortmsgs end] + append lastmsg "\n [string repeat " " 12] [join $secondline { / }]" + set shortmsgs [list {*}[lrange $shortmsgs 0 end-1] $lastmsg] + } + set lastappend "" + set lastmsg [lindex $shortmsgs end] + set shortmsgs [lrange $shortmsgs 0 end-1] + foreach shortmsg $shortmsgs { + set lines [split [textutil::adjust::adjust $shortmsg -full true -justify left -length 120 -strictlength true] \n] + lappend lastappend " [string repeat " " 10] * [pop lines]" + foreach line $lines { + lappend lastappend " [string repeat " " 12] $line" + } + } + set lines [split [textutil::adjust::adjust $shortmsg -full true -justify left -length 120 -strictlength true] \n] + lappend lastappend " %%CHANGELOGDATE%% * [pop lines]" + foreach line $lines { + lappend lastappend " [string repeat " " 10] * $line" + } + if {[dict exists $tags $commit]} { + lappend lastappend "\nEggdrop [dict get $tags $commit] (released $date):\n" + set forcedate 1 + } + set lastdate $date + } + lappend result {*}[string map [list %%CHANGELOGDATE%% $lastdate] $lastappend] + puts "Eggdrop Changes (Last Updated [clock format [clock seconds] -gmt 1 -format "%Y-%m-%d"]):\n__________________________________________\n\nEggdrop v$version:\n" + puts [join [lreverse $result] \n] +} + +start