update-versions.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #!/usr/bin/python
  2. # Copyright 2018 Google
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """update-versions.py creates a release branch and commit with version updates.
  16. With the required --version parameter, this script will update all files in
  17. the repo based on the versions in Releases/Manifests/{version}.json.
  18. It will create a release branch, push and tag the updates, and push the
  19. updated podspecs to cpdc-internal.
  20. """
  21. import argparse
  22. import json
  23. import os
  24. import subprocess
  25. import sys
  26. import tempfile
  27. test_mode = False # Flag to disable external repo updates
  28. def SetupArguments():
  29. """SetupArguments sets up the set of command-line arguments.
  30. Returns:
  31. Args: The set of command line arguments
  32. """
  33. parser = argparse.ArgumentParser(description='Update Pod Versions')
  34. parser.add_argument('--version', required=True, help='Firebase version')
  35. parser.add_argument(
  36. '--test_mode',
  37. dest='test_mode',
  38. action='store_true',
  39. help='Log commands instead of updating public repo')
  40. parser.add_argument(
  41. '--tag_update',
  42. dest='tag_update',
  43. action='store_true',
  44. help='Update the tags only')
  45. parser.add_argument(
  46. '--base_branch',
  47. dest='base_branch',
  48. default='master',
  49. help='Base branch for new release')
  50. parser.add_argument(
  51. '--push_only',
  52. dest='push_only',
  53. action='store_true',
  54. help='Skip all of script except pushing podspecs to cpdc_internal')
  55. args = parser.parse_args()
  56. return args
  57. def LogOrRun(command):
  58. """Log or run a command depending on test_mode value.
  59. Args:
  60. command: command to log or run.
  61. """
  62. if test_mode:
  63. print 'Log only: {}'.format(command)
  64. else:
  65. os.system(command)
  66. def GetVersionData(git_root, version):
  67. """Update version specifier in FIROptions.m.
  68. Args:
  69. git_root: root of git checkout.
  70. version: the next version to release.
  71. Returns:
  72. Dictionary with pod keys and version values.
  73. """
  74. json_file = os.path.join(git_root, 'Releases', 'Manifests',
  75. '{}.json'.format(version))
  76. if os.path.isfile(json_file):
  77. return json.load(open(json_file))
  78. else:
  79. sys.exit('Missing version file:{}'.format(json_file))
  80. def CreateReleaseBranch(release_branch, base_branch):
  81. """Create and push the release branch.
  82. Args:
  83. release_branch: the name of the git release branch.
  84. """
  85. os.system('git checkout {}'.format(base_branch))
  86. os.system('git pull')
  87. os.system('git checkout -b {}'.format(release_branch))
  88. LogOrRun('git push origin {}'.format(release_branch))
  89. LogOrRun('git branch --set-upstream-to=origin/{} {}'.format(release_branch,
  90. release_branch))
  91. def UpdatePodSpecs(git_root, version_data, firebase_version):
  92. """Update the podspecs with the right version.
  93. Args:
  94. git_root: root of git checkout.
  95. version_data: dictionary of versions to be updated.
  96. firebase_version: the Firebase version.
  97. """
  98. core_podspec = os.path.join(git_root, 'FirebaseCore.podspec')
  99. os.system("sed -i.bak -e \"s/\\(Firebase_VERSION=\\).*'/\\1{}'/\" {}".format(
  100. firebase_version, core_podspec))
  101. for pod, version in version_data.items():
  102. podspec = os.path.join(git_root, '{}.podspec'.format(pod))
  103. os.system("sed -i.bak -e \"s/\\(\\.version.*=[[:space:]]*'\\).*'/\\1{}'/\" "
  104. '{}'.format(version, podspec))
  105. def UpdatePodfiles(git_root, version):
  106. """Update Podfile's to reference the latest Firebase pod.
  107. Args:
  108. git_root: root of git checkout.
  109. version: the next Firebase version to release.
  110. """
  111. firebase_podfile = os.path.join(git_root, 'Example', 'Podfile')
  112. firestore_podfile = os.path.join(git_root, 'Firestore', 'Example', 'Podfile')
  113. collision_podfile = os.path.join(git_root, 'SymbolCollisionTest', 'Podfile')
  114. sed_command = ("sed -i.bak -e \"s#\\(pod "
  115. "'Firebase/CoreOnly',[[:space:]]*'\\).*'#\\1{}'#\" {}")
  116. os.system(sed_command.format(version, firebase_podfile))
  117. os.system(sed_command.format(version, firestore_podfile))
  118. sed_command = ("sed -i.bak -e \"s#\\(pod "
  119. "'Firebase',[[:space:]]*'\\).*'#\\1{}'#\" {}")
  120. os.system(sed_command.format(version, collision_podfile))
  121. def GenerateTag(pod, version):
  122. """ Generate a tag from a pod and a version.
  123. Args:
  124. pod: name of the pod for which to generate the tag.
  125. version: version of the pod to tag.
  126. Returns:
  127. Tag.
  128. """
  129. if pod.startswith("Firebase"):
  130. return '{}-{}'.format(pod[len('Firebase'):], version)
  131. if pod.startswith("Google"):
  132. return '{}-{}'.format(pod[len('Google'):], version)
  133. sys.exit("Script does not support generating a tag for {}".format(pod))
  134. def UpdateTags(version_data, firebase_version, first=False):
  135. """Update tags.
  136. Args:
  137. version_data: dictionary of versions to be updated.
  138. firebase_version: the Firebase version.
  139. first: set to true the first time the versions are set.
  140. """
  141. if not first:
  142. LogOrRun("git push --delete origin '{}'".format(firebase_version))
  143. LogOrRun("git tag --delete '{}'".format(firebase_version))
  144. LogOrRun("git tag '{}'".format(firebase_version))
  145. LogOrRun("git push origin '{}'".format(firebase_version))
  146. for pod, version in version_data.items():
  147. tag = GenerateTag(pod, version)
  148. if not first:
  149. LogOrRun("git push --delete origin '{}'".format(tag))
  150. LogOrRun("git tag --delete '{}'".format(tag))
  151. LogOrRun("git tag '{}'".format(tag))
  152. LogOrRun("git push origin '{}'".format(tag))
  153. def CheckVersions(version_data):
  154. """Ensure that versions do not already exist as tags.
  155. Args:
  156. version_data: dictionary of versions to be updated.
  157. """
  158. error = False
  159. for pod, version in version_data.items():
  160. tag = GenerateTag(pod, version)
  161. find = subprocess.Popen(
  162. ['git', 'tag', '-l', tag],
  163. stdout=subprocess.PIPE).communicate()[0].rstrip()
  164. if tag == find:
  165. print "{} tag already exists".format(tag)
  166. error = True
  167. if error:
  168. sys.exit("Aborting: Remove pre-existing tags and retry")
  169. def GetCpdcInternal():
  170. """Find the firebase repo.
  171. """
  172. tmp_file = tempfile.mktemp()
  173. os.system('pod repo list | grep -B2 sso://cpdc-internal/firebase | head -1 > {}'
  174. .format(tmp_file))
  175. with open(tmp_file,'r') as o:
  176. output_var = ''.join(o.readlines()).strip()
  177. os.system('rm -rf {}'.format(tmp_file))
  178. return output_var
  179. def PushPodspecs(version_data):
  180. """Push podspecs to cpdc-firebase.
  181. Args:
  182. version_data: dictionary of versions to be updated.
  183. """
  184. pods = version_data.keys()
  185. pods.insert(0, pods.pop(pods.index('FirebaseCore'))) # Core should be first
  186. tmp_dir = tempfile.mkdtemp()
  187. for pod in pods:
  188. LogOrRun('pod cache clean {} --all'.format(pod))
  189. if pod == 'FirebaseFirestore':
  190. warnings_ok = ' --allow-warnings'
  191. else:
  192. warnings_ok = ''
  193. podspec = '{}.podspec'.format(pod)
  194. json = os.path.join(tmp_dir, '{}.json'.format(podspec))
  195. LogOrRun('pod ipc spec {} > {}'.format(podspec, json))
  196. LogOrRun('pod repo push --skip-tests {} {}{}'.format(GetCpdcInternal(),
  197. json, warnings_ok))
  198. os.system('rm -rf {}'.format(tmp_dir))
  199. def UpdateVersions():
  200. """UpdateVersions is the main body to create the branch and change versions.
  201. """
  202. global test_mode
  203. args = SetupArguments()
  204. test_mode = args.test_mode
  205. # Validate version is proper format
  206. major, minor, patch = args.version.split('.')
  207. if (not major.isdigit()) or (not minor.isdigit()) or (not patch.isdigit()):
  208. sys.exit('Invalid version parameter')
  209. git_root = subprocess.Popen(
  210. ['git', 'rev-parse', '--show-toplevel'],
  211. stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')
  212. version_data = GetVersionData(git_root, args.version)
  213. if not args.push_only:
  214. if args.tag_update:
  215. UpdateTags(version_data, args.version)
  216. return
  217. CheckVersions(version_data)
  218. release_branch = 'release-{}'.format(args.version)
  219. CreateReleaseBranch(release_branch, args.base_branch)
  220. UpdatePodSpecs(git_root, version_data, args.version)
  221. UpdatePodfiles(git_root, args.version)
  222. LogOrRun('git commit -am "Update versions for Release {}"'
  223. .format(args.version))
  224. LogOrRun('git push origin {}'.format(release_branch))
  225. UpdateTags(version_data, args.version, True)
  226. PushPodspecs(version_data)
  227. if __name__ == '__main__':
  228. UpdateVersions()