gitlab.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3. """
  4. @Contact : liuyuqi.gov@msn.cn
  5. @Time : 2023/09/27 12:16:56
  6. @License : Copyright © 2017-2022 liuyuqi. All Rights Reserved.
  7. @Desc : gitlab async
  8. """
  9. import os
  10. import json
  11. import re
  12. import csv
  13. import subprocess
  14. from .base_platform import BasePlatform
  15. from repo_sync.models import Repo
  16. from repo_sync.utils.logger import logger
  17. class GitlabIE(BasePlatform):
  18. """gitlab async"""
  19. def __init__(self, username: str, token: str, host: str = None, params: dict = None) -> None:
  20. super().__init__(username=username, token=token)
  21. self.host = host or 'https://gitlab.com'
  22. self.sess.headers.update({"Authorization": f"Bearer {self.token}"})
  23. self.repo_private = 'private' if params.get('gitlab_private', "true").lower() == 'true' else 'public'
  24. def create_repo(self, repo_name: str):
  25. """create a repo
  26. and save project id to csv: gitlab_repo_list.csv
  27. """
  28. if not self._repo_exists(repo_name):
  29. url = f"{self.host}/api/v4/projects"
  30. payload = {
  31. "name": repo_name,
  32. "visibility": self.repo_private,
  33. }
  34. r = self.sess.post(url, data=json.dumps(payload))
  35. if r.status_code != 201:
  36. logger.error(f"create repo {repo_name} failed, status code {r.status_code}")
  37. return
  38. logger.info(f"create repo {repo_name} success")
  39. logger.info(f'{self.host}/{self.username}/{repo_name}')
  40. # for repo in self.repos:
  41. # if repo.name == repo_name:
  42. # repo.url = r.json()["web_url"]
  43. # repo.id = r.json()["id"]
  44. # break
  45. # self.save_csv()
  46. def delete(self, repo_name: str):
  47. """delete a repo,
  48. find project id from csv: gitlab_repo_list.csv
  49. """
  50. project_id = ""
  51. r = self.sess.get(f"{self.host}/api/v4/users/{self.username}/projects?search={repo_name}")
  52. if r.status_code == 200:
  53. try:
  54. project_id = r.json()[0]["id"]
  55. url = f"{self.host}/api/v4/projects/{project_id}"
  56. response = self.sess.delete(url)
  57. if response.status_code == 202:
  58. logger.info(f"Repository: {repo_name} deleted from gitlab successfully!")
  59. else:
  60. logger.error(
  61. f"Failed to delete repository: {repo_name} from gitlab. Error {response.status_code}: {response.text}"
  62. )
  63. except Exception as e:
  64. logger.error(f"Failed to delete repository: {repo_name} from gitlab. Error {e}, check repo is exist first.")
  65. else:
  66. logger.error(f"Failed to delete repository: {repo_name} from gitlab. Error {r.status_code}: {r.text}")
  67. def get_repo_list(self, username: str) -> list:
  68. """get repo list"""
  69. url = f"{self.host}/api/v4/users/{username}/projects"
  70. r = self.sess.get(url)
  71. if r.status_code != 200:
  72. logger.error(f"get repo list failed, status code {r.status_code}")
  73. return []
  74. repo_list = []
  75. for res in r.json():
  76. repo = Repo()
  77. repo.name = res["name"]
  78. repo.url = res["web_url"]
  79. repo.local_path = None
  80. repo.id = res["id"]
  81. repo_list.append(repo)
  82. self.save_csv()
  83. return repo_list
  84. def pull(self, local_repo_path: str):
  85. """push a local repo to remote
  86. Args:
  87. local_repo_path (str): local repo path
  88. """
  89. if local_repo_path[-1] == os.path.sep:
  90. local_repo_path = local_repo_path[:-1]
  91. repo_name = local_repo_path.split(os.path.sep)[-1]
  92. logger.info(f"pull repo:{self.username}/{repo_name} from gitlab")
  93. self.create_repo(repo_name)
  94. pur_host = re.search(r'(?<=//)[^/]+', self.host).group()
  95. os.chdir(local_repo_path)
  96. os.system("git remote remove origin_gitlab")
  97. os.system(
  98. f"git remote add origin_gitlab https://{self.username}:{self.token}@{pur_host}/{self.username}/{repo_name}.git"
  99. )
  100. result = subprocess.run(
  101. ['git', 'symbolic-ref', '--short', 'HEAD'], capture_output=True, text=True, encoding='utf-8')
  102. current_branch = result.stdout.strip()
  103. os.system(f'git pull origin_gitlab {current_branch}')
  104. os.system("git remote remove origin_gitlab")
  105. os.chdir("..")
  106. logger.info(f"pull repo:{self.username}/{repo_name} from gitlab success")
  107. def push(self, local_repo_path: str):
  108. """push a local repo to remote
  109. Args:
  110. local_repo_path (str): local repo path
  111. """
  112. if local_repo_path[-1] == os.path.sep:
  113. local_repo_path = local_repo_path[:-1]
  114. repo_name = local_repo_path.split(os.path.sep)[-1]
  115. logger.info(f"push repo:{self.username}/{repo_name} to gitlab")
  116. self.create_repo(repo_name)
  117. pur_host = re.search(r'(?<=//)[^/]+', self.host).group()
  118. os.chdir(local_repo_path)
  119. os.system("git remote remove origin_gitlab")
  120. os.system(
  121. f"git remote add origin_gitlab https://{self.username}:{self.token}@{pur_host}/{self.username}/{repo_name}.git"
  122. )
  123. result = subprocess.run(
  124. ['git', 'symbolic-ref', '--short', 'HEAD'], capture_output=True, text=True, encoding='utf-8')
  125. current_branch = result.stdout.strip()
  126. os.system(f'git pull origin_gitlab {current_branch}')
  127. os.system(f"git push -u origin_gitlab {current_branch}")
  128. os.system("git remote remove origin_gitlab")
  129. os.chdir("..")
  130. logger.info(f"push repo:{self.username}/{repo_name} to gitlab success")
  131. def clone(self):
  132. pass
  133. def _repo_exists(self, repo_name: str):
  134. """ check if a repo exists
  135. if not exist, return [] empty list
  136. """
  137. project_id = ""
  138. r = self.sess.get(f"{self.host}/api/v4/users/{self.username}/projects?search={repo_name}")
  139. if r.status_code == 200:
  140. try:
  141. project_id = r.json()[0]["id"]
  142. logger.info(f'repo: {repo_name} is existed.')
  143. return True
  144. except Exception as e:
  145. return False
  146. @classmethod
  147. def suitable(cls, extractor: str) -> bool:
  148. """check if this extractor is suitable for this platform"""
  149. return extractor == 'gitlab'