github.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. from github import Github
  18. from github import GithubException
  19. from traitlets.config import LoggingConfigurable
  20. from urllib3.util import parse_url
  21. class GithubClient(LoggingConfigurable):
  22. def __init__(
  23. self,
  24. token: str,
  25. repo: str,
  26. branch: Optional[str] = None,
  27. server_url: Optional[str] = "https://api.github.com",
  28. **kwargs,
  29. ):
  30. """
  31. Creates a Github Client for Elyra
  32. :param token: Personal Access Token for use with Github
  33. See https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token
  34. :param repo: Github Repository to use. Use Form : [Github Username/Org]/[Repository Name]
  35. e.g. elyra/examples
  36. :param branch: Branch in the 'repo' to use. If not provided, this will use the default branch configured in the
  37. target repository
  38. :param server_url: Github API endpoint to use for the client. This is can be an Enterprise
  39. Github instance. By default the client will attempt to connect to the main Github API at
  40. https://api.github.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.repo_name = repo
  46. self.branch = branch
  47. self.client = Github(login_or_token=token, base_url=self.server_url)
  48. try:
  49. self.github_repository = self.client.get_repo(self.repo_name)
  50. except GithubException as e:
  51. self.log.error(f'Error accessing repository {self.repo_name}: {e.data["message"]} ({e.status})')
  52. raise RuntimeError(
  53. f'Error accessing repository {self.repo_name}: {e.data["message"]} ({e.status}). '
  54. "Please validate your runtime configuration details and retry."
  55. ) from e
  56. def upload_dag(self, pipeline_filepath: str, pipeline_name: str) -> None:
  57. """
  58. Push a DAG to a remote Github Repository
  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 remote Github Repository
  61. :return:
  62. """
  63. try:
  64. # Upload to github
  65. with open(pipeline_filepath) as input_file:
  66. content = input_file.read()
  67. self.github_repository.create_file(
  68. path=pipeline_name + ".py",
  69. message="Pushed DAG " + pipeline_name,
  70. content=content,
  71. branch=self.branch,
  72. )
  73. self.log.info("Pipeline successfully added to the git queue")
  74. except FileNotFoundError as fnfe:
  75. self.log.error(f"Unable to locate local DAG file to upload: {pipeline_filepath}: " + str(fnfe))
  76. raise RuntimeError(f"Unable to locate local DAG file to upload: {pipeline_filepath}: {str(fnfe)}") from fnfe
  77. except GithubException as e:
  78. self.log.error(f'Error uploading DAG to branch {self.branch}: {e.data["message"]} ({e.status})')
  79. raise RuntimeError(
  80. f'Error uploading DAG to branch {self.branch}: {e.data["message"]} ({e.status}). '
  81. "Please validate your runtime configuration details and retry."
  82. ) from e
  83. @staticmethod
  84. def get_git_url(api_url: str, repository_name: str, repository_branch: str) -> str:
  85. """
  86. Generates the URL to the location of the pushed DAG
  87. :param api_url: url of the GitHub API
  88. :param repository_name: name of the GitHub repository in the form [name or org]/[repository name]
  89. :param repository_branch: name of the GitHub branch
  90. :return: a URL in string format
  91. """
  92. parsed_url = parse_url(api_url)
  93. scheme = parsed_url.scheme + ":/"
  94. host = parsed_url.host
  95. port = ""
  96. if parsed_url.host.split(".")[0] == "api":
  97. host = ".".join(parsed_url.host.split(".")[1:])
  98. if parsed_url.port:
  99. port = ":" + parsed_url.port
  100. return "/".join([scheme, host + port, repository_name, "tree", repository_branch])