summaryrefslogtreecommitdiffstats
path: root/release/sign-tag.py
diff options
context:
space:
mode:
Diffstat (limited to 'release/sign-tag.py')
-rwxr-xr-xrelease/sign-tag.py171
1 files changed, 99 insertions, 72 deletions
diff --git a/release/sign-tag.py b/release/sign-tag.py
index 605437c9..fbfe7b26 100755
--- a/release/sign-tag.py
+++ b/release/sign-tag.py
@@ -35,46 +35,61 @@ import util
35KEYID = util.KEYID_DSA 35KEYID = util.KEYID_DSA
36 36
37# Regular expression to validate tag names. 37# Regular expression to validate tag names.
38RE_VALID_TAG = r'^v([0-9]+[.])+[0-9]+$' 38RE_VALID_TAG = r"^v([0-9]+[.])+[0-9]+$"
39 39
40 40
41def sign(opts): 41def sign(opts):
42 """Tag the commit & sign it!""" 42 """Tag the commit & sign it!"""
43 # We use ! at the end of the key so that gpg uses this specific key. 43 # We use ! at the end of the key so that gpg uses this specific key.
44 # Otherwise it uses the key as a lookup into the overall key and uses the 44 # Otherwise it uses the key as a lookup into the overall key and uses the
45 # default signing key. i.e. It will see that KEYID_RSA is a subkey of 45 # default signing key. i.e. It will see that KEYID_RSA is a subkey of
46 # another key, and use the primary key to sign instead of the subkey. 46 # another key, and use the primary key to sign instead of the subkey.
47 cmd = ['git', 'tag', '-s', opts.tag, '-u', f'{opts.key}!', 47 cmd = [
48 '-m', f'repo {opts.tag}', opts.commit] 48 "git",
49 49 "tag",
50 key = 'GNUPGHOME' 50 "-s",
51 print('+', f'export {key}="{opts.gpgdir}"') 51 opts.tag,
52 oldvalue = os.getenv(key) 52 "-u",
53 os.putenv(key, opts.gpgdir) 53 f"{opts.key}!",
54 util.run(opts, cmd) 54 "-m",
55 if oldvalue is None: 55 f"repo {opts.tag}",
56 os.unsetenv(key) 56 opts.commit,
57 else: 57 ]
58 os.putenv(key, oldvalue) 58
59 key = "GNUPGHOME"
60 print("+", f'export {key}="{opts.gpgdir}"')
61 oldvalue = os.getenv(key)
62 os.putenv(key, opts.gpgdir)
63 util.run(opts, cmd)
64 if oldvalue is None:
65 os.unsetenv(key)
66 else:
67 os.putenv(key, oldvalue)
59 68
60 69
61def check(opts): 70def check(opts):
62 """Check the signature.""" 71 """Check the signature."""
63 util.run(opts, ['git', 'tag', '--verify', opts.tag]) 72 util.run(opts, ["git", "tag", "--verify", opts.tag])
64 73
65 74
66def postmsg(opts): 75def postmsg(opts):
67 """Helpful info to show at the end for release manager.""" 76 """Helpful info to show at the end for release manager."""
68 cmd = ['git', 'rev-parse', 'remotes/origin/stable'] 77 cmd = ["git", "rev-parse", "remotes/origin/stable"]
69 ret = util.run(opts, cmd, encoding='utf-8', stdout=subprocess.PIPE) 78 ret = util.run(opts, cmd, encoding="utf-8", stdout=subprocess.PIPE)
70 current_release = ret.stdout.strip() 79 current_release = ret.stdout.strip()
71 80
72 cmd = ['git', 'log', '--format=%h (%aN) %s', '--no-merges', 81 cmd = [
73 f'remotes/origin/stable..{opts.tag}'] 82 "git",
74 ret = util.run(opts, cmd, encoding='utf-8', stdout=subprocess.PIPE) 83 "log",
75 shortlog = ret.stdout.strip() 84 "--format=%h (%aN) %s",
76 85 "--no-merges",
77 print(f""" 86 f"remotes/origin/stable..{opts.tag}",
87 ]
88 ret = util.run(opts, cmd, encoding="utf-8", stdout=subprocess.PIPE)
89 shortlog = ret.stdout.strip()
90
91 print(
92 f"""
78Here's the short log since the last release. 93Here's the short log since the last release.
79{shortlog} 94{shortlog}
80 95
@@ -84,57 +99,69 @@ NB: People will start upgrading to this version immediately.
84 99
85To roll back a release: 100To roll back a release:
86 git push origin --force {current_release}:stable -n 101 git push origin --force {current_release}:stable -n
87""") 102"""
103 )
88 104
89 105
90def get_parser(): 106def get_parser():
91 """Get a CLI parser.""" 107 """Get a CLI parser."""
92 parser = argparse.ArgumentParser( 108 parser = argparse.ArgumentParser(
93 description=__doc__, 109 description=__doc__,
94 formatter_class=argparse.RawDescriptionHelpFormatter) 110 formatter_class=argparse.RawDescriptionHelpFormatter,
95 parser.add_argument('-n', '--dry-run', 111 )
96 dest='dryrun', action='store_true', 112 parser.add_argument(
97 help='show everything that would be done') 113 "-n",
98 parser.add_argument('--gpgdir', 114 "--dry-run",
99 default=os.path.join(util.HOMEDIR, '.gnupg', 'repo'), 115 dest="dryrun",
100 help='path to dedicated gpg dir with release keys ' 116 action="store_true",
101 '(default: ~/.gnupg/repo/)') 117 help="show everything that would be done",
102 parser.add_argument('-f', '--force', action='store_true', 118 )
103 help='force signing of any tag') 119 parser.add_argument(
104 parser.add_argument('--keyid', dest='key', 120 "--gpgdir",
105 help='alternative signing key to use') 121 default=os.path.join(util.HOMEDIR, ".gnupg", "repo"),
106 parser.add_argument('tag', 122 help="path to dedicated gpg dir with release keys "
107 help='the tag to create (e.g. "v2.0")') 123 "(default: ~/.gnupg/repo/)",
108 parser.add_argument('commit', default='HEAD', nargs='?', 124 )
109 help='the commit to tag') 125 parser.add_argument(
110 return parser 126 "-f", "--force", action="store_true", help="force signing of any tag"
127 )
128 parser.add_argument(
129 "--keyid", dest="key", help="alternative signing key to use"
130 )
131 parser.add_argument("tag", help='the tag to create (e.g. "v2.0")')
132 parser.add_argument(
133 "commit", default="HEAD", nargs="?", help="the commit to tag"
134 )
135 return parser
111 136
112 137
113def main(argv): 138def main(argv):
114 """The main func!""" 139 """The main func!"""
115 parser = get_parser() 140 parser = get_parser()
116 opts = parser.parse_args(argv) 141 opts = parser.parse_args(argv)
117 142
118 if not os.path.exists(opts.gpgdir): 143 if not os.path.exists(opts.gpgdir):
119 parser.error(f'--gpgdir does not exist: {opts.gpgdir}') 144 parser.error(f"--gpgdir does not exist: {opts.gpgdir}")
120 145
121 if not opts.force and not re.match(RE_VALID_TAG, opts.tag): 146 if not opts.force and not re.match(RE_VALID_TAG, opts.tag):
122 parser.error(f'tag "{opts.tag}" does not match regex "{RE_VALID_TAG}"; ' 147 parser.error(
123 'use --force to sign anyways') 148 f'tag "{opts.tag}" does not match regex "{RE_VALID_TAG}"; '
149 "use --force to sign anyways"
150 )
124 151
125 if opts.key: 152 if opts.key:
126 print(f'Using custom key to sign: {opts.key}') 153 print(f"Using custom key to sign: {opts.key}")
127 else: 154 else:
128 print('Using official Repo release key to sign') 155 print("Using official Repo release key to sign")
129 opts.key = KEYID 156 opts.key = KEYID
130 util.import_release_key(opts) 157 util.import_release_key(opts)
131 158
132 sign(opts) 159 sign(opts)
133 check(opts) 160 check(opts)
134 postmsg(opts) 161 postmsg(opts)
135 162
136 return 0 163 return 0
137 164
138 165
139if __name__ == '__main__': 166if __name__ == "__main__":
140 sys.exit(main(sys.argv[1:])) 167 sys.exit(main(sys.argv[1:]))