Skip to content

Commit b8e80d8

Browse files
authored
Merge pull request #3528 from adbridge/master
Modify update command to directly edit the mbed-os.lib files for each example
2 parents fd52695 + fb27b64 commit b8e80d8

File tree

1 file changed

+182
-110
lines changed

1 file changed

+182
-110
lines changed

tools/test/examples/update.py

Lines changed: 182 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import subprocess
99
import shutil
1010
import stat
11+
import re
12+
from github import Github, GithubException
1113

1214
ROOT = abspath(dirname(dirname(dirname(dirname(__file__)))))
1315
sys.path.insert(0, ROOT)
@@ -33,6 +35,26 @@ def run_cmd(command, print_warning_on_fail=True):
3335

3436
return return_code
3537

38+
def run_cmd_with_output(command, print_warning_on_fail=True):
39+
""" Takes the command specified and runs it in a sub-process, obtaining the return code
40+
and the returned output.
41+
42+
Args:
43+
command - command to run, provided as a list of individual fields which are combined into a
44+
single command before passing to the sub-process call.
45+
return_code - result of the command.
46+
output - the output of the command
47+
48+
"""
49+
print('[Exec] %s' % ' '.join(command))
50+
returncode = 0
51+
output = None
52+
try:
53+
output = subprocess.check_output(command)
54+
except subprocess.CalledProcessError as e:
55+
print("The command '%s' failed with return code: %s" % (' '.join(command), e.returncode))
56+
returncode = e.returncode
57+
return returncode, output
3658

3759
def rmtree_readonly(directory):
3860
""" Deletes a readonly directory tree.
@@ -63,7 +85,7 @@ def find_all_examples(path):
6385

6486
return examples
6587

66-
def upgrade_single_example(example, tag, directory):
88+
def upgrade_single_example(example, tag, directory, ref):
6789
""" Updates the mbed-os.lib file in the example specified to correspond to the
6890
version specified by the GitHub tag supplied. Also deals with
6991
multiple sub-examples in the GitHub repo, updating them in the same way.
@@ -72,113 +94,157 @@ def upgrade_single_example(example, tag, directory):
7294
example - json example object containing the GitHub repo to update.
7395
tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
7496
directory - directory path for the example.
97+
ref - SHA corresponding to the supplied tag
7598
returns - True if the upgrade was successful, False otherwise.
7699
77100
"""
78-
print("Upgrading single example at path '%s'" % directory)
79101
cwd = os.getcwd()
80102
os.chdir(directory)
81103

82-
return_code = None
83-
84-
# Change directories to the mbed-os library
85-
if not os.path.exists('mbed-os'):
86-
print("'mbed-os' directory not found in the root of '%s'" % directory)
87-
print("Ignoring and moving on to the next example")
88-
os.chdir(cwd)
89-
return False
104+
return_code = False
90105

91-
os.chdir('mbed-os')
92-
93-
# Setup and run the update command
94-
update_cmd = ['mbed', 'update', tag]
95-
return_code = run_cmd(update_cmd)
96-
97-
if return_code:
98-
os.chdir(cwd)
106+
if os.path.isfile("mbed-os.lib"):
107+
# Rename command will fail on some OS's if the target file already exist,
108+
# so ensure if it does, it is deleted first.
109+
if os.path.isfile("mbed-os.lib_bak"):
110+
os.remove("mbed-os.lib_bak")
111+
112+
os.rename("mbed-os.lib", "mbed-os.lib_bak")
113+
else:
114+
print("!! Error trying to backup mbed-os.lib prior to updating.")
99115
return False
100116

101-
os.chdir('../')
102-
103-
# Setup and run the add command
104-
add_cmd = ['git', 'add', 'mbed-os.lib']
105-
return_code = run_cmd(add_cmd)
117+
# mbed-os.lib file contains one line with the following format
118+
# e.g. https://github.com/ARMmbed/mbed-os/#0789928ee7f2db08a419fa4a032fffd9bd477aa7
119+
lib_re = re.compile('https://github.com/ARMmbed/mbed-os/#[A-Za-z0-9]+')
120+
updated = False
121+
122+
# Scan through mbed-os.lib line by line
123+
with open('mbed-os.lib_bak', 'r') as ip, open('mbed-os.lib', 'w') as op:
124+
for line in ip:
125+
126+
opline = line
127+
128+
regexp = lib_re.match(line)
129+
if regexp:
130+
opline = 'https://github.com/ARMmbed/mbed-os/#' + ref
131+
updated = True
106132

133+
op.write(opline)
134+
135+
if updated:
136+
# Setup and run the git add command
137+
cmd = ['git', 'add', 'mbed-os.lib']
138+
return_code = run_cmd(cmd)
139+
107140
os.chdir(cwd)
108141
return not return_code
109142

110-
def upgrade_example(example, tag):
111-
""" Clones the example specified from GitHub and updates the associated mbed-os.lib file
112-
to correspond to the version specified by the GitHub tag supplied. Also deals with
113-
multiple sub-examples in the GitHub repo, updating them in the same way.
143+
def prepare_fork(arm_example):
144+
""" Synchronises a cloned fork to ensure it is up to date with the original.
145+
146+
Args:
147+
arm_example - Full GitHub repo path for original example
148+
ret - True if the fork was synchronised successfully, False otherwise
149+
150+
"""
151+
152+
print "In " + os.getcwd()
153+
154+
for cmd in [['git', 'remote', 'add', 'armmbed', arm_example],
155+
['git', 'fetch', 'armmbed'],
156+
['git', 'reset', '--hard', 'armmbed/master'],
157+
['git', 'push', '-f', 'origin']]:
158+
if run_cmd(cmd):
159+
print("preparation of the fork failed!")
160+
return False
161+
return True
162+
163+
164+
def upgrade_example(github, example, tag, user, ref):
165+
""" Clone a fork of the example specified.
166+
Ensures the fork is up to date with the original and then and updates the associated
167+
mbed-os.lib file on that fork to correspond to the version specified by the GitHub tag supplied.
168+
Also deals with multiple sub-examples in the GitHub repo, updating them in the same way.
169+
The updates are pushed to the forked repo.
170+
Finally a PR is raised against the original example repo for the changes.
114171
115172
Args:
173+
github - GitHub instance to allow internal git commands to be run
116174
example - json example object containing the GitHub repo to update.
117175
tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
176+
user - GitHub user name
177+
ref - SHA corresponding to the tag
118178
119179
"""
120-
print("Updating example '%s'" % example['name'])
180+
ret = False
181+
print("\nUpdating example '%s'" % example['name'])
121182
cwd = os.getcwd()
122-
123-
# Setup and run the import command
124-
clone_cmd = ['git', 'clone', example['github']]
125-
return_code = run_cmd(clone_cmd)
126-
127-
if return_code:
183+
184+
full_repo_name = 'ARMmbed/'+ example['name']
185+
fork = "https://github.com/" + user + '/' + example['name']
186+
187+
# Check access to mbed-os repo
188+
try:
189+
repo = github.get_repo(full_repo_name, False)
190+
191+
except:
192+
print("\t\t!! Repo does not exist - skipping\n")
128193
return False
194+
195+
196+
# Clone the forked example repo
197+
clone_cmd = ['git', 'clone', fork]
198+
return_code = run_cmd(clone_cmd)
129199

130-
# Find all examples
131-
example_directories = find_all_examples(example['name'])
132-
133-
os.chdir(example['name'])
134-
135-
# Setup and run the update command
136-
import_cmd = ['mbed', 'update']
137-
return_code = run_cmd(import_cmd)
138-
if return_code:
139-
os.chdir(cwd)
140-
return False
200+
if not return_code:
141201

142-
for example_directory in example_directories:
143-
if not upgrade_single_example(example, tag, os.path.relpath(example_directory, example['name'])):
144-
os.chdir(cwd)
145-
return False
202+
# Find all examples
203+
example_directories = find_all_examples(example['name'])
146204

147-
# Setup the default commit message
148-
commit_message = 'Updating mbed-os to {{' + tag +'}}'
205+
os.chdir(example['name'])
206+
207+
# checkout and synchronise the release-candidate branch
208+
prepare_fork(example['github'])
209+
210+
for example_directory in example_directories:
211+
if not upgrade_single_example(example, tag, os.path.relpath(example_directory, example['name']), ref):
212+
os.chdir(cwd)
213+
return False
214+
215+
# Setup the default commit message
216+
commit_message = 'Updating mbed-os to ' + tag
217+
218+
# Setup and run the commit command
219+
commit_cmd = ['git', 'commit', '-m', commit_message]
220+
return_code = run_cmd(commit_cmd)
221+
if not return_code:
222+
223+
# Setup and run the push command
224+
push_cmd = ['git', 'push', 'origin']
225+
return_code = run_cmd(push_cmd)
149226

150-
# Setup and run the commit command
151-
commit_cmd = ['git', 'commit', '-m', commit_message]
152-
return_code = run_cmd(commit_cmd)
153-
if return_code:
154-
if return_code == 1:
155-
print("[WARNING] 'git commit' exited with a return code of 1. " + \
156-
"This usually inidicates that no update was made. Still " + \
157-
"attempting to create a tag.")
227+
if not return_code:
228+
body = "Please test/merge this PR and then tag Master with " + tag
229+
# Raise a PR from release-candidate to master
230+
user_fork = user + ':master'
231+
try:
232+
pr = repo.create_pull(title='Updating mbed-os to ' + tag, head=user_fork, base='master', body=body)
233+
ret = True
234+
except GithubException as e:
235+
# Default to False
236+
print("Creation of Pull Request from release-candidate to master failed with the following error!")
237+
print e
238+
else:
239+
print("!!! Git push command failed.")
158240
else:
159-
os.chdir(cwd)
160-
return False
161-
162-
# Setup and run the tag command
163-
tag_cmd = ['git', 'tag', '-a', tag, '-m', tag]
164-
return_code = run_cmd(tag_cmd)
165-
if return_code:
166-
os.chdir(cwd)
167-
return False
168-
169-
# Setup and run the push command
170-
push_cmd = ['git', 'push', 'origin', 'master']
171-
return_code = run_cmd(push_cmd)
172-
173-
if return_code:
174-
os.chdir(cwd)
175-
return False
176-
177-
push_cmd = ['git', 'push', 'origin', tag]
178-
return_code = run_cmd(push_cmd)
179-
241+
print("!!! Git commit command failed.")
242+
else:
243+
print("!!! Could not clone user fork %s\n" % fork)
244+
245+
180246
os.chdir(cwd)
181-
return not return_code
247+
return ret
182248

183249
def create_work_directory(path):
184250
""" Create a new directory specified in 'path', overwrite if the directory already
@@ -220,11 +286,27 @@ def test_compile(config, tag):
220286

221287

222288
def main(arguments):
289+
""" Will update any mbed-os.lib files found in the example list specified by the config file.
290+
If no config file is specified the default 'examples.json' is used.
291+
The update is done by cloning a fork of each example (the fork must be present in the
292+
github account specified by the github user parameter). The fork is searched for any
293+
mbed-os.lib files and each one found is updated with the SHA corresponding to the supplied
294+
github tag. A pull request is then made from the fork to the original example repo.
295+
296+
Args:
297+
tag - tag to update the mbed-os.lib to. E.g. mbed-os-5.3.1
298+
github_token - Pre-authorised token to allow github access
299+
github_user - github username whose account contains the example forks
300+
config_file - optional parameter to specify a list of examples
301+
302+
"""
223303

224304
parser = argparse.ArgumentParser(description=__doc__,
225305
formatter_class=argparse.RawDescriptionHelpFormatter)
226306
parser.add_argument('tag', help="mbed-os tag to which all examples will be updated")
227307
parser.add_argument('-c', '--config_file', help="Path to the configuration file (default is 'examples.json')", default='examples.json')
308+
parser.add_argument('-T', '--github_token', help="GitHub token for secure access")
309+
parser.add_argument('-U', '--github_user', help="GitHub user for forked repos")
228310

229311
args = parser.parse_args(arguments)
230312

@@ -238,45 +320,41 @@ def main(arguments):
238320
print("Failed to load config file '%s'" % args.config_file)
239321
sys.exit(1)
240322

241-
# Create work directories
323+
# Create working directory
242324
create_work_directory('examples')
243-
325+
326+
github = Github(args.github_token)
327+
328+
# Get the github sha corresponding to the specified mbed-os tag
329+
cmd = ['git', 'rev-list', '-1', args.tag]
330+
return_code, ref = run_cmd_with_output(cmd)
331+
332+
if return_code:
333+
print("Could not obtain SHA for tag: %s\n" % args.tag)
334+
sys.exit(1)
335+
244336
# Loop through the examples
245337
failures = []
246338
successes = []
247-
not_compiled = []
248339
results = {}
249340
os.chdir('examples')
250-
251-
results = test_compile(config, args.tag)
252-
lib.print_compilation_summary(results)
253341

254342
for example in config['examples']:
255-
# Determine if this example should be updated
256-
257-
# Attempt to update if:
258-
# group of examples passed compilation and
259-
# auto update is set to True
260-
# Note: results fields are [compiled flag, pass flag, successes list, failures list]
261-
if not results[example['name']][0]:
262-
# Example was not compiled
263-
not_compiled += [example['name']]
343+
# Determine if this example should be updated and if so update any found
344+
# mbed-os.lib files.
345+
346+
if upgrade_example(github, example, args.tag, args.github_user, ref):
347+
successes += [example['name']]
264348
else:
265-
if results[example['name']][1] and example['auto-update']:
266-
if upgrade_example(example, args.tag):
267-
successes += [example['name']]
268-
else:
269-
failures += [example['name']]
270-
else:
271-
failures += [example['name']]
349+
failures += [example['name']]
272350

273351
os.chdir('../')
274352

275353
# Finish the script and report the results
276354
print(os.linesep + os.linesep +'Finished updating examples!' + os.linesep)
277355

278356
if successes:
279-
print('The following examples updated successfully:')
357+
print('\nThe following examples updated successfully:')
280358
for success in successes:
281359
print(' - %s' % success)
282360

@@ -285,11 +363,5 @@ def main(arguments):
285363
for fail in failures:
286364
print(' - %s' % fail)
287365

288-
if not_compiled:
289-
print('The following examples were skipped:')
290-
for example in not_compiled:
291-
print(' - %s' % example)
292-
293-
294366
if __name__ == '__main__':
295367
sys.exit(main(sys.argv[1:]))

0 commit comments

Comments
 (0)