version_manipulation.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import os
  2. import re
  3. import requests
  4. from itertools import groupby
  5. from github import Github
  6. from github.GithubException import GithubException
  7. repos_URL = {
  8. "stable": "netdata/netdata",
  9. "nightly": "netdata/netdata-nightlies"
  10. }
  11. GH_TOKEN = os.getenv("GH_TOKEN")
  12. if GH_TOKEN is None or GH_TOKEN != "":
  13. print("Token is not defined or empty, continuing with limitation on requests per sec towards Github API")
  14. def identify_channel(_version):
  15. nightly_pattern = r'v(\d+)\.(\d+)\.(\d+)-(\d+)-nightly'
  16. stable_pattern = r'v(\d+)\.(\d+)\.(\d+)'
  17. if re.match(nightly_pattern, _version):
  18. _channel = "nightly"
  19. _pattern = nightly_pattern
  20. elif re.match(stable_pattern, _version):
  21. _channel = "stable"
  22. _pattern = stable_pattern
  23. else:
  24. print("Invalid version format.")
  25. return None
  26. return _channel, _pattern
  27. def padded_version(item):
  28. key_value = '10000'
  29. for value in item[1:]:
  30. key_value += f'{value:05}'
  31. return int(key_value)
  32. def extract_version(title):
  33. if identify_channel(title):
  34. _, _pattern = identify_channel(title)
  35. try:
  36. match = re.match(_pattern, title)
  37. if match:
  38. return tuple(map(int, match.groups()))
  39. except Exception as e:
  40. print(f"Unexpected error: {e}")
  41. return None
  42. def get_release_path_and_filename(_version):
  43. nightly_pattern = r'v(\d+)\.(\d+)\.(\d+)-(\d+)-nightly'
  44. stable_pattern = r'v(\d+)\.(\d+)\.(\d+)'
  45. if match := re.match(nightly_pattern, _version):
  46. msb = match.group(1)
  47. _path = "nightly"
  48. _filename = f"v{msb}"
  49. elif match := re.match(stable_pattern, _version):
  50. msb = match.group(1)
  51. _path = "stable"
  52. _filename = f"v{msb}"
  53. else:
  54. print("Invalid version format.")
  55. exit(1)
  56. return (_path, _filename)
  57. def compare_version_with_remote(version):
  58. """
  59. If the version = fun (version) you need to update the version in the
  60. remote. If the version remote doesn't exist, returns the version
  61. :param channel: any version of the agent
  62. :return: the greater from version and version remote.
  63. """
  64. prefix = "https://packages.netdata.cloud/releases"
  65. path, filename = get_release_path_and_filename(version)
  66. remote_url = f"{prefix}/{path}/{filename}"
  67. response = requests.get(remote_url)
  68. if response.status_code == 200:
  69. version_remote = response.text.rstrip()
  70. version_components = extract_version(version)
  71. remote_version_components = extract_version(version_remote)
  72. absolute_version = padded_version(version_components)
  73. absolute_remote_version = padded_version(remote_version_components)
  74. if absolute_version > absolute_remote_version:
  75. print(f"Version in the remote: {version_remote}, is older than the current: {version}, I need to update")
  76. return (version)
  77. else:
  78. print(f"Version in the remote: {version_remote}, is newer than the current: {version}, no action needed")
  79. return (None)
  80. else:
  81. # Remote version not found
  82. print(f"Version in the remote not found, updating the predefined latest path with the version: {version}")
  83. return (version)
  84. def sort_and_grouby_major_agents_of_channel(channel):
  85. """
  86. Fetches the GH API and read either netdata/netdata or netdata/netdata-nightlies repo. It fetches all of their
  87. releases implements a grouping by their major release number.
  88. Every k,v in this dictionary is in the form; "vX": [descending ordered list of Agents in this major release].
  89. :param channel: "nightly" or "stable"
  90. :return: None or dict() with the Agents grouped by major version # (vX)
  91. """
  92. try:
  93. G = Github(GH_TOKEN)
  94. repo = G.get_repo(repos_URL[channel])
  95. releases = repo.get_releases()
  96. except GithubException as e:
  97. print(f"GitHub API request failed: {e}")
  98. return None
  99. except Exception as e:
  100. print(f"An unexpected error occurred: {e}")
  101. return None
  102. extracted_titles = [extract_version(item.title) for item in releases if
  103. extract_version(item.title) is not None]
  104. # Necessary sorting for implement the group by
  105. extracted_titles.sort(key=lambda x: x[0])
  106. # Group titles by major version
  107. grouped_by_major = {major: list(group) for major, group in groupby(extracted_titles, key=lambda x: x[0])}
  108. sorted_grouped_by_major = {}
  109. for key, values in grouped_by_major.items():
  110. sorted_values = sorted(values, key=padded_version, reverse=True)
  111. sorted_grouped_by_major[key] = sorted_values
  112. # Transform them in the correct form
  113. if channel == "stable":
  114. result_dict = {f"v{key}": [f"v{a}.{b}.{c}" for a, b, c in values] for key, values in
  115. sorted_grouped_by_major.items()}
  116. else:
  117. result_dict = {f"v{key}": [f"v{a}.{b}.{c}-{d}-nightly" for a, b, c, d in values] for key, values in
  118. sorted_grouped_by_major.items()}
  119. return result_dict