Small fixups for micro-release (now: tag-fixes-release) script
[exim.git] / release-process / scripts / tag-fixes-release
1 #!/usr/bin/perl
2
3 use v5.10.1;
4 use strict;
5 use warnings;
6 use feature 'say';
7 use Getopt::Long;
8 use File::Temp qw(tempfile);
9 use Pod::Usage;
10
11 my $BRANCH_PATTERN = qr/^
12     (?<base>(?<name>exim)-
13     (?<version>
14     (?<major>\d+)
15     _(?<minor>\d+)
16     )(?:_(?<security>\d+))?
17     )\+fixes/x;
18
19 sub trim { return join '', shift =~ /^\s*(.*?)\s*$/; }
20
21 my %o = (edit => 1, dotted => 1, force => 0, auto => 0);
22
23 GetOptions(
24     \%o,
25     'edit!',
26     'dotted!',
27     'force!', 'auto!',
28     'help|h' => sub { pod2usage(-verbose => 1, -exit => 0) },
29     'man|m'  => sub {
30         pod2usage(
31             -verbose   => 2,
32             -exit      => 0,
33             -noperldoc => system('perldoc -V >/dev/null 2>&1')
34         );
35     },
36 ) or pod2usage;
37
38 my $branch = trim `git rev-parse --abbrev-ref HEAD`;    # exim-4_90+fixes
39 die "$0: Branch `$branch` does not match `$BRANCH_PATTERN`"
40   unless "$branch" =~ /$BRANCH_PATTERN/;
41
42 my $name = $+{name};
43 my $base = $+{base};    # exim-4_90 (branch base)
44
45 my $release_legacy = $+{version} . ($+{security} // '_0');    # 4.90_0
46 my $release_dotted = join '.', $+{major}, $+{minor}, $+{security} // 0; # 4.90.0
47
48 my $distance = trim `git rev-list --count $base..`;
49
50 my $micro_legacy = "${release_legacy}_$distance";    # 4_90_0_20
51 my $micro_dotted = "${release_dotted}.$distance";    # 4.90.0.20
52
53 my $tag = "$name-" . ($o{dotted} ? $micro_dotted : $micro_legacy);
54
55 # check if the tag already exists
56 if (not $o{force}) {
57     `git rev-parse --quiet --verify '$tag'`;         # ignore stdout
58     die "$0: tag '$tag' exists already\n" if $? == 0;
59 }
60
61 my ($fh, $filename) = tempfile();
62 print $fh <<XXX;
63 Exim fixup release $micro_dotted
64 # Enter a one line tag description. The above is the sensible default.
65 XXX
66 close $fh;
67
68 system(
69       defined $ENV{VISUAL} ? $ENV{VISUAL}
70     : defined $ENV{EDITOR} ? $ENV{EDITOR}
71     :                        'vi' => $filename
72   ) == 0
73   or exit $? >> 8
74   if $o{edit};
75
76 if (not $o{auto}) {
77     print "Commit tag `$tag` to local repository? [Y/n] ";
78     exit 0 unless <STDIN> =~ /^(:?y(?:es)?|)$/i;
79 }
80
81 system(
82     git => 'tag',
83     '--sign', ($o{force} ? '--force' : ()),
84     -a => $tag,
85     -F => $filename,
86   ) == 0
87   or exit $? >> 8;
88
89 system(
90     git        => 'tag',
91     '--verify' => $tag
92   ) == 0
93   or exit $? >> 8;
94
95 say "\nDo not forget to `git push --follow-tags ...` now."
96
97 __END__
98
99 =head1 NAME
100
101  tag-fixes-release - tag the current commit on a +fixes branch
102
103 =head1 SYNOPSIS
104
105  tag-fixes-release [--[no]-edit] [--[no]-dotted] [--force]
106
107 =head1 DESCRIPTION
108
109 This B<tag-fixes-release> tools is for internal use only. It tags the
110 current commit of a F<+fixes> branch as a "micro release".
111
112 The tag is calculated from the branch name and the distance to the
113 branch tag. The branch name needs to match the branch tag.
114
115     branch tag:    exim-4_90
116     branch name:   exim-4_90+fixes
117     resulting tag: exim-4.90.0.<distance>   (dotted version)
118                    exim-4_90_0_<distance>   (classic version)
119
120     branch tag:    exim-4_90_1   (security release)
121     branch name:   exim-4_90_1+fixes
122     resulting tag: exim-4.90.1.<distance>   (dotted version)
123                    exim-4_90_1_<distance>   (classic version)
124
125 The tag will be GPG signed.
126
127 =head1 OPTIONS
128
129 =over
130
131 =item B<--[no]-edit>
132
133 Spawn or do not spawn an editor. The default message will be "Exim
134 <tagname> fixup release".
135
136 =item B<--dotted>
137
138 Generate a dotted tag name. (default: on)
139
140 =item B<--force>
141
142 (Re)Move an existing tag name. Use with care!
143
144 =item B<-h>|B<--help>
145
146 Short help.
147
148 =item B<-m>|B<--man>
149
150 The manual page.
151
152 =back
153
154 =cut