checkout_project_ref.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #!/usr/bin/env python
  2. # internal use only
  3. # called by CI jobs when it uses a project related to IDF
  4. import argparse
  5. import json
  6. import os
  7. import re
  8. import subprocess
  9. IDF_GIT_DESCRIBE_PATTERN = re.compile(r'^v(\d)\.(\d)')
  10. RETRY_COUNT = 3
  11. def get_customized_project_revision(proj_name):
  12. """
  13. get customized project revision defined in bot message
  14. """
  15. revision = ''
  16. customized_project_revisions = os.getenv('BOT_CUSTOMIZED_REVISION')
  17. if customized_project_revisions:
  18. customized_project_revisions = json.loads(customized_project_revisions)
  19. try:
  20. revision = customized_project_revisions[proj_name.lower()]
  21. except (KeyError, TypeError):
  22. pass
  23. return revision
  24. def target_branch_candidates(proj_name):
  25. """
  26. :return: a list of target branch candidates, from highest priority to lowest priority.
  27. """
  28. candidates = [
  29. # branch name (or tag name) of current IDF
  30. os.getenv('CI_COMMIT_REF_NAME'),
  31. # CI_MERGE_REQUEST_TARGET_BRANCH_NAME
  32. os.getenv('CI_MERGE_REQUEST_TARGET_BRANCH_NAME'),
  33. ]
  34. customized_candidate = get_customized_project_revision(proj_name)
  35. if customized_candidate:
  36. # highest priority, insert to head of list
  37. candidates.insert(0, customized_candidate)
  38. # branch name read from IDF
  39. try:
  40. git_describe = subprocess.check_output(['git', 'describe', 'HEAD'])
  41. match = IDF_GIT_DESCRIBE_PATTERN.search(git_describe.decode())
  42. if match:
  43. major_revision = match.group(1)
  44. minor_revision = match.group(2)
  45. # release branch
  46. candidates.append('release/v{}.{}'.format(major_revision, minor_revision))
  47. # branch to match all major branches, like v3.x or v3
  48. candidates.append('release/v{}.x'.format(major_revision))
  49. candidates.append('release/v{}'.format(major_revision))
  50. except subprocess.CalledProcessError:
  51. # this should not happen as IDF should have describe message
  52. pass
  53. return [c for c in candidates if c] # filter out null value
  54. if __name__ == '__main__':
  55. parser = argparse.ArgumentParser()
  56. parser.add_argument('project',
  57. help='the name of project')
  58. parser.add_argument('project_relative_path',
  59. help='relative path of project to IDF repository directory')
  60. parser.add_argument('--customized_only', action='store_true',
  61. help='Only to find customized revision')
  62. args = parser.parse_args()
  63. if args.customized_only:
  64. customized_revision = get_customized_project_revision(args.project)
  65. candidate_branches = [customized_revision] if customized_revision else []
  66. else:
  67. candidate_branches = target_branch_candidates(args.project)
  68. # change to project dir for checkout
  69. os.chdir(args.project_relative_path)
  70. ref_to_use = ''
  71. for candidate in candidate_branches:
  72. # check if candidate branch exists
  73. branch_match = subprocess.check_output(['git', 'branch', '-a', '--list', 'origin/' + candidate])
  74. if branch_match:
  75. ref_to_use = candidate
  76. break
  77. if ref_to_use:
  78. for _ in range(RETRY_COUNT):
  79. # Add retry for projects with git-lfs
  80. try:
  81. subprocess.check_call(['git', 'checkout', '-f', ref_to_use], stdout=subprocess.PIPE) # not print the stdout
  82. print('CI using ref {} for project {}'.format(ref_to_use, args.project))
  83. break
  84. except subprocess.CalledProcessError:
  85. pass
  86. else:
  87. print('Failed to use ref {} for project {}'.format(ref_to_use, args.project))
  88. exit(1)
  89. else:
  90. print('using default branch')