update_dependencies 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/env python3
  2. import argparse
  3. import errno
  4. import os
  5. import subprocess
  6. from collections import defaultdict
  7. ITEMS = defaultdict(lambda: {'success': [], 'error': []})
  8. class ValidationException(Exception):
  9. def __init__(self, error_msg, error_no=errno.EFAULT):
  10. self.errmsg = error_msg
  11. self.errno = error_no
  12. def get_error_name(self):
  13. return errno.errorcode.get(self.errno) or 'EUNKNOWN'
  14. def __str__(self):
  15. return f'[{self.get_error_name()}] {self.errmsg}'
  16. class NotFoundException(ValidationException):
  17. def __init__(self, error):
  18. super().__init__(error, errno.ENOENT)
  19. class TrainNotFoundException(NotFoundException):
  20. def __init__(self):
  21. super(TrainNotFoundException, self).__init__('Failed to find train')
  22. class CatalogItemNotFoundException(NotFoundException):
  23. def __init__(self, path):
  24. super(CatalogItemNotFoundException, self).__init__(f'Failed to find {path!r} catalog item')
  25. def report_result():
  26. print('[\033[94mINFO\x1B[0m]\tExecution Complete')
  27. for index, item in enumerate(ITEMS):
  28. index += 1
  29. data = ITEMS[item]
  30. print(f'\n[\033[94mINFO\x1B[0m]\t{index}) {item}')
  31. if data['success']:
  32. print(
  33. f'[\033[92mOK\x1B[0m]\t - Successfully updated dependencies for {", ".join(data["success"])} versions'
  34. )
  35. for i_v, version in enumerate(data['error']):
  36. v_name, error = version
  37. print(
  38. f'[\033[91mFAILED\x1B[0m]\t ({i_v + 1}) Failed to update dependencies for {v_name!r} version: {error}'
  39. )
  40. def update_train_charts(train_path, commit):
  41. # We will gather all charts in the train and then for each chart all it's versions will be updated
  42. if not os.path.exists(train_path):
  43. raise TrainNotFoundException()
  44. print(f'[\033[94mINFO\x1B[0m]\tProcessing {train_path!r} train')
  45. for item in os.listdir(train_path):
  46. process_catalog_item(os.path.join(train_path, item))
  47. report_result()
  48. if commit and any(ITEMS[item]['success'] for item in ITEMS):
  49. if any(ITEMS[item]['error'] for item in ITEMS):
  50. print(f'[\033[91mFAILED\x1B[0m]\tNot committing changes as failures detected')
  51. else:
  52. commit_msg = f'Updated catalog item dependencies ({train_path.rsplit("/", 1)[-1]} train)\n' \
  53. 'Following items were updated:\n'
  54. for item in ITEMS:
  55. commit_msg += f'Updated {item} ({", ".join(ITEMS[item]["success"])} versions)\n\n'
  56. for cmd in (
  57. ['git', '-C', train_path, 'add', train_path],
  58. ['git', '-C', train_path, 'commit', '-m', commit_msg]
  59. ):
  60. cp = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
  61. stderr = cp.communicate()[1]
  62. if cp.returncode:
  63. print(f'[\033[91mFAILED\x1B[0m]\tFailed to execute {" ".join(cmd)}: {stderr.decode()}')
  64. exit(1)
  65. print('[\033[92mOK\x1B[0m]\tChanges committed successfully')
  66. def process_catalog_item(item_path):
  67. if not os.path.exists(item_path):
  68. raise CatalogItemNotFoundException(item_path)
  69. item_name = item_path.rsplit('/', 1)[-1]
  70. print(f'[\033[94mINFO\x1B[0m]\tProcessing {item_name!r} catalog item')
  71. for item_version in os.listdir(item_path):
  72. if os.path.isdir(os.path.join(item_path, item_version)):
  73. update_item_version(item_name, item_version, os.path.join(item_path, item_version))
  74. def update_item_version(item_name, version, version_path):
  75. cp = subprocess.Popen(
  76. ['helm', 'dependency', 'update', version_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE
  77. )
  78. stdout, stderr = cp.communicate()
  79. if cp.returncode:
  80. ITEMS[item_name]['error'].append((version, stderr.decode()))
  81. else:
  82. ITEMS[item_name]['success'].append(version)
  83. def main():
  84. parser = argparse.ArgumentParser()
  85. subparsers = parser.add_subparsers(help='sub-command help', dest='action')
  86. parser_setup = subparsers.add_parser('update', help='Update dependencies for specified train')
  87. parser_setup.add_argument('--train', help='Specify train path to update dependencies', required=True)
  88. parser_setup.add_argument('--commit', help='Commit after updating dependencies', default=False)
  89. args = parser.parse_args()
  90. if args.action == 'update':
  91. update_train_charts(args.train, args.commit)
  92. else:
  93. parser.print_help()
  94. if __name__ == '__main__':
  95. main()