Merge lp:~abentley/juju-core/sign-branch-op into lp:~juju-qa/juju-core/cd-release-juju

Proposed by Aaron Bentley
Status: Merged
Merged at revision: 263
Proposed branch: lp:~abentley/juju-core/sign-branch-op
Merge into: lp:~juju-qa/juju-core/cd-release-juju
Diff against target: 253 lines (+125/-21)
4 files modified
operation_sign_branch.py (+68/-0)
release-juju.bash (+16/-0)
sign_branch.py (+24/-8)
tests/test_sign_branch.py (+17/-13)
To merge this branch: bzr merge lp:~abentley/juju-core/sign-branch-op
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+284977@code.launchpad.net

Commit message

Support branch signing from release-juju.bash

Description of the change

This branch adds support for branch signing to release-juju.bash

It renames release-juju.bash to operation-release-juju.bash, and replaces it with a simple script that either calls operation-release-juju.bash or operation_sign_branch.py, depending on the specified operation.

It updates sign_branch.py to use a revision-id parameter.

It creates operation_sign_branch.py that functions much like the old release-juju.bash, except in python and for signing branches.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'release-juju.bash' => 'operation-release-juju.bash'
2=== added file 'operation_sign_branch.py'
3--- operation_sign_branch.py 1970-01-01 00:00:00 +0000
4+++ operation_sign_branch.py 2016-02-03 21:49:03 +0000
5@@ -0,0 +1,68 @@
6+#!/usr/bin/env python
7+import datetime
8+import errno
9+import os
10+import subprocess
11+import sys
12+
13+unsigned_branch = "lp:~juju-qa/+junk/cpc-unsigned"
14+revision_id = 'aaron@aaronbentley.com-20160202205534-70syvicq77vnl326'
15+signed_branch = "lp:~juju-qa/+junk/cpc-signed"
16+signing_key = os.environ.get('SIGNING_KEY', '6A157DB3')
17+poke = 0
18+
19+
20+def acquire_log_dir():
21+ """Return the path of the log dir, creating if need be."""
22+ tools_base = os.environ.get('TOOLS_BASE')
23+ if tools_base is None:
24+ tools_base = os.getcwd()
25+ log_dir = os.path.join(tools_base, 'new-tools', 'juju-dist', 'tools')
26+ if not os.path.exists(log_dir):
27+ os.makedirs(log_dir)
28+ return log_dir
29+
30+
31+def check_log(parameters):
32+ """Check for a previous entry with the same parameters in the log.
33+
34+ If one exists, return False. Otherwise, log the parameters.
35+
36+ This is deliberately done before attempting the operation, to avoid
37+ endless retries if the operation fails.
38+ """
39+ log_dir = acquire_log_dir()
40+ log_filename = os.path.join(log_dir, 'sign-branch.log')
41+ log_entry = ' '.join(parameters + [''])
42+ try:
43+ log_branch = open(log_filename)
44+ except IOError as e:
45+ if e.errno != errno.ENOENT:
46+ raise
47+ else:
48+ with log_branch:
49+ for line in log_branch:
50+ if line.startswith(log_entry):
51+ return False
52+ with open(log_filename, 'a') as log_branch:
53+ now = datetime.datetime.utcnow().replace(microsecond=0)
54+ strdate = now.isoformat(' ')
55+ log_branch.write('{}{}\n'.format(log_entry, strdate))
56+ return True
57+
58+
59+def main():
60+ parameters = [revision_id, unsigned_branch, signed_branch, signing_key,
61+ str(poke)]
62+ if not check_log(parameters):
63+ sys.exit(0)
64+ scripts = os.path.dirname(__file__)
65+ sign_branch = os.path.join(scripts, 'sign_branch.py')
66+ args = [sign_branch, unsigned_branch, revision_id, signed_branch,
67+ signing_key]
68+ print ' '.join(args)
69+ subprocess.call(args)
70+
71+
72+if __name__ == '__main__':
73+ main()
74
75=== added file 'release-juju.bash'
76--- release-juju.bash 1970-01-01 00:00:00 +0000
77+++ release-juju.bash 2016-02-03 21:49:03 +0000
78@@ -0,0 +1,16 @@
79+#!/bin/bash
80+set -eu
81+scripts=$(readlink -f $(dirname $0))
82+operation="release"
83+case "${operation}" in
84+ "release" )
85+ $scripts/operation-release-juju.bash
86+ ;;
87+ "sign-branch" )
88+ $scripts/operation_sign_branch.py
89+ ;;
90+ * )
91+ echo "Unknown operation $operation"
92+ exit 1
93+ ;;
94+esac
95
96=== modified file 'sign_branch.py'
97--- sign_branch.py 2016-02-02 18:00:35 +0000
98+++ sign_branch.py 2016-02-03 21:49:03 +0000
99@@ -14,13 +14,25 @@
100 self.bzr_home = bzr_home
101 self.quiet = quiet
102
103- def bzr(self, command, *args):
104+ @staticmethod
105+ def get_args(command, args):
106 cc_args = ['bzr', '--no-aliases']
107 cc_args.append(command)
108 cc_args.extend(args)
109+ return cc_args
110+
111+ def get_env(self):
112 env = dict(os.environ)
113 if self.bzr_home is not None:
114 env['BZR_HOME'] = self.bzr_home
115+ return env
116+
117+ def get_output(self, command, *args):
118+ cmd_args = self.get_args(command, args)
119+ return subprocess.check_output(cmd_args, env=self.get_env())
120+
121+ def bzr(self, command, *args):
122+ cc_args = self.get_args(command, args)
123 with open('/dev/null', 'w') as null:
124 if self.quiet:
125 err = null
126@@ -28,14 +40,16 @@
127 else:
128 err = None
129 out = None
130- subprocess.check_call(cc_args, env=env, stderr=err, stdout=out)
131+ subprocess.check_call(cc_args, env=self.get_env(), stderr=err,
132+ stdout=out)
133
134
135 class SignBranch:
136
137- def __init__(self, unsigned_branch, signed_branch, temp_branch,
138- signing_key, signing_passphrase_file, bzr):
139+ def __init__(self, unsigned_branch, revision_id, signed_branch,
140+ temp_branch, signing_key, signing_passphrase_file, bzr):
141 self.unsigned_branch = unsigned_branch
142+ self.revision_id = revision_id
143 self.signed_branch = signed_branch
144 self.temp_branch = temp_branch
145 self.signing_key = signing_key
146@@ -43,7 +57,8 @@
147 self.bzr = bzr
148
149 def merge(self):
150- self.bzr.bzr('merge', '-d', self.temp_branch, self.unsigned_branch)
151+ self.bzr.bzr('merge', '-d', self.temp_branch, self.unsigned_branch,
152+ '-r', 'revid:{}'.format(self.revision_id))
153 # Ensure nothing left behind.
154 self.bzr.bzr('clean-tree', '-d', self.temp_branch, '--force',
155 '--ignored', '--unknown')
156@@ -70,6 +85,7 @@
157 def parse_args(argv=None):
158 parser = ArgumentParser()
159 parser.add_argument('unsigned', help='The unsigned branch to sign')
160+ parser.add_argument('revision_id', help='The revision-id to sign')
161 parser.add_argument('signed', help='The signed branch to update')
162 parser.add_argument('signing_key', help='Key to sign with.')
163 parser.add_argument('-p', '--signing-passphrase-file',
164@@ -80,9 +96,9 @@
165 def main():
166 args = parse_args()
167 with temp_dir() as temp_branch:
168- sb = SignBranch(args.unsigned, args.signed, temp_branch,
169- args.signing_key, args.signing_passphrase_file,
170- RunBzr())
171+ sb = SignBranch(args.unsigned, args.revision_id, args.signed,
172+ temp_branch, args.signing_key,
173+ args.signing_passphrase_file, RunBzr())
174 sb.sign_branch()
175
176
177
178=== modified file 'tests/test_sign_branch.py'
179--- tests/test_sign_branch.py 2016-02-02 18:00:35 +0000
180+++ tests/test_sign_branch.py 2016-02-03 21:49:03 +0000
181@@ -38,14 +38,15 @@
182 class TestParseArgs(TestCase):
183
184 def test_minimum(self):
185- args = parse_args(['unsigned1', 'signed1', 'key1'])
186+ args = parse_args(['unsigned1', 'revid', 'signed1', 'key1'])
187 self.assertEqual(
188- Namespace(unsigned='unsigned1', signed='signed1',
189- signing_key='key1', signing_passphrase_file=None),
190+ Namespace(
191+ unsigned='unsigned1', revision_id='revid', signed='signed1',
192+ signing_key='key1', signing_passphrase_file=None),
193 args)
194
195 def test_passphrase_file(self):
196- args = parse_args(['unsigned1', 'signed1', 'key1',
197+ args = parse_args(['unsigned1', 'revid', 'signed1', 'key1',
198 '--signing-passphrase-file', 'foo'])
199 self.assertEqual('foo', args.signing_passphrase_file)
200
201@@ -74,7 +75,9 @@
202 json_file.write(self.get_example_json())
203 bzr.bzr('add', filename)
204 bzr.bzr('commit', unsigned_branch, '-m', 'Add foo.json')
205- return unsigned_branch, signed_branch
206+ revision_info = bzr.get_output('revision-info', '-d', unsigned_branch)
207+ revision_id = revision_info.split(' ')[1].rstrip('\n')
208+ return unsigned_branch, revision_id, signed_branch
209
210 def test_sign_branch(self):
211 with temp_dir() as temp_root:
212@@ -82,12 +85,12 @@
213 os.mkdir(bzr_home)
214 bzr = RunBzr(bzr_home, quiet=True)
215 bzr.bzr('whoami', 'J Random Hacker <jrandom@example.org>')
216- unsigned_branch, signed_branch = self.prepare_branches(bzr,
217- temp_root)
218+ unsigned_branch, revision_id, signed_branch = (
219+ self.prepare_branches(bzr, temp_root))
220 with temp_dir() as temp_branch:
221 sign_branch = SignBranch(
222- unsigned_branch, signed_branch, temp_branch, None, None,
223- bzr)
224+ unsigned_branch, revision_id, signed_branch, temp_branch,
225+ None, None, bzr)
226 with patch('sign_metadata.run', autospec=True,
227 side_effect=fake_gpg):
228 sign_branch.sign_branch()
229@@ -100,10 +103,11 @@
230
231 def test_clean_after_merge(self):
232 bzr = MagicMock()
233- sb = SignBranch('unsigned', 'signed', 'temp', None, None, bzr)
234+ sb = SignBranch('unsigned', 'rev-id', 'signed', 'temp', None, None,
235+ bzr)
236 sb.merge()
237 self.assertEqual([
238- call('merge', '-d', 'temp', 'unsigned'),
239+ call('merge', '-d', 'temp', 'unsigned', '-r', 'revid:rev-id'),
240 call('clean-tree', '-d', 'temp', '--force', '--ignored',
241 '--unknown'),
242 ], bzr.bzr.mock_calls)
243@@ -121,8 +125,8 @@
244 foo.write('')
245 with open(os.path.join(v1_dir, 'baz.json.gpg'), 'w') as foo:
246 foo.write('')
247- sb = SignBranch('unsigned', 'signed', temp_branch, None, None,
248- None)
249+ sb = SignBranch('unsigned', 'rev-id', 'signed', temp_branch, None,
250+ None, None)
251 with patch('sign_metadata.run', autospec=True,
252 side_effect=fake_gpg):
253 sb.sign_metadata()

Subscribers

People subscribed via source and target branches