gitlab.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #
  2. # Copyright 2018-2022 Elyra Authors
  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. #
  16. from typing import Optional
  17. # this may raise an ImportError if the python-gitlab package is not installed
  18. from gitlab import Gitlab
  19. # this may raise an ImportError if the python-gitlab package is not installed
  20. from gitlab.exceptions import GitlabError # noqa H306
  21. from traitlets.config import LoggingConfigurable
  22. from urllib3.util import parse_url
  23. class GitLabClient(LoggingConfigurable):
  24. def __init__(
  25. self,
  26. token: str,
  27. project: str,
  28. branch: Optional[str] = None,
  29. server_url: Optional[str] = "https://gitlab.com",
  30. **kwargs,
  31. ):
  32. """
  33. Creates a GitLab client for Elyra
  34. :param token: Personal Access Token for use with GitLab
  35. :param project: GitLab project to use. Use format [namespace]/[project] e.g. elyra/examples
  36. :param branch: Project branch to use. If not provided, this will use the default branch configured in the
  37. target project
  38. :param server_url: GitLab API endpoint to use for the client. This is can be an Enterprise
  39. GitLab instance. By default the client will attempt to connect to the main GitLab API at
  40. https://www.gitlab.com'
  41. """
  42. super().__init__(**kwargs)
  43. # Remove trailing slash(es) from server URL to prevent failure
  44. self.server_url = server_url.rstrip("/")
  45. self.project_name = project
  46. self.branch = branch
  47. try:
  48. self.client = Gitlab(self.server_url, private_token=token)
  49. self.gitlab_project = self.client.projects.get(self.project_name)
  50. except GitlabError as gle:
  51. self.log.error(f"Error accessing project {self.project_name}: {gle}")
  52. raise RuntimeError(
  53. f"Error accessing repository {self.project_name}: {gle}. "
  54. "Please validate your runtime configuration details and retry."
  55. ) from gle
  56. def upload_dag(self, pipeline_filepath: str, pipeline_name: str) -> None:
  57. """
  58. Push a DAG to a gitlab project
  59. :param pipeline_filepath: filepath to the location of the DAG in the local filesystem
  60. :param pipeline_name: the name of the file to be created in the gitlab project
  61. :return:
  62. """
  63. try:
  64. # Upload DAG to gitlab project
  65. with open(pipeline_filepath) as input_file:
  66. content = input_file.read()
  67. git_file_name = f"{pipeline_name}.py"
  68. self.gitlab_project.files.create(
  69. {
  70. "file_path": git_file_name,
  71. "branch": self.branch,
  72. "content": content,
  73. "commit_message": f"Pushed DAG {pipeline_name}",
  74. }
  75. )
  76. self.log.info(f"DAG file {git_file_name} was successfully uploaded to branch {self.branch}.")
  77. except FileNotFoundError as fnfe:
  78. self.log.error(f"Unable to locate local DAG file to upload: {pipeline_filepath}: " + str(fnfe))
  79. raise RuntimeError(f"Unable to locate local DAG file to upload: {pipeline_filepath}: {str(fnfe)}") from fnfe
  80. except GitlabError as gle:
  81. self.log.error(f"Error uploading DAG to branch {self.branch}: {gle}")
  82. raise RuntimeError(
  83. f"Error uploading DAG to branch {self.branch}: {gle} "
  84. "Please validate your runtime configuration details and try again."
  85. ) from gle
  86. @staticmethod
  87. def get_git_url(api_url: str, repository_name: str, repository_branch: str) -> str:
  88. """
  89. Generates the URL to the location of the pushed DAG
  90. :param api_url: git API endpoint URL
  91. :param project_name: name of the GitLab project in the form [namespace]/[project]
  92. :param project_branch: name of the project branch
  93. :return: a URL in string format
  94. """
  95. parsed_url = parse_url(api_url)
  96. scheme = f"{parsed_url.scheme}://"
  97. host = parsed_url.host
  98. port = ""
  99. if parsed_url.host.split(".")[0] == "api":
  100. host = ".".join(parsed_url.host.split(".")[1:])
  101. if parsed_url.port:
  102. port = f":{parsed_url.port}"
  103. return f"{scheme}{host}{port}/{repository_name}/tree/{repository_branch}"