FOSSology  4.4.0
Open Source License Compliance by Open Source Software
RepoSetup.py
1 #!/usr/bin/env python3
2 
3 # SPDX-FileCopyrightText: © 2023 Siemens AG
4 # SPDX-FileContributor: Gaurav Mishra <mishra.gaurav@siemens.com>
5 
6 # SPDX-License-Identifier: GPL-2.0-only
7 
8 import fnmatch
9 import json
10 import os
11 import re
12 import ssl
13 import urllib.request
14 from tempfile import TemporaryDirectory
15 from typing import Union
16 
17 from .ApiConfig import ApiConfig, Runner
18 from .CliOptions import CliOptions
19 
20 
21 class RepoSetup:
22  """
23  Setup temp_dir using the diff or current MR
24 
25  :ivar temp_dir: Temporary directory location for storing MR changes.
26  :ivar allowlist: Allow list from JSON
27  :ivar api_config: ApiConfig
28  """
29 
30  def __init__(self, cli_options: CliOptions, api_config: ApiConfig):
31  """
32  Create a temp dir
33 
34  :param cli_options: CliOptions object to get allow list from
35  :param api_config: API configuration for the CI
36  """
37  self.temp_dir: Union[TemporaryDirectory[str], TemporaryDirectory[bytes]] \
38  = TemporaryDirectory()
39  self.allowlist: dict[str, list[str]] = cli_options.allowlist
40  self.api_config: ApiConfig = api_config
41 
42  def __del__(self):
43  """
44  Clean the created temp dir
45  """
46  self.temp_dir.cleanup()
47 
48  def __is_excluded_path(self, path: str) -> bool:
49  """
50  Check if the path is allow listed
51 
52  The function used fnmatch to check if the path is in allow list or not.
53 
54  :param path: path to check
55  :return: True if the path is in allow list, False otherwise
56  """
57  path_is_excluded = False
58  for pattern in self.allowlist['exclude']:
59  if fnmatch.fnmatchcase(path, pattern):
60  path_is_excluded = True
61  break
62  return path_is_excluded
63 
64  def get_diff_dir(self) -> str:
65  """
66  Populate temp dir using the gitlab API `merge_requests`
67 
68  :return: temp dir path
69  """
70  if self.api_config.running_on == Runner.GITLAB:
71  api_req_url = f"{self.api_config.api_url}/projects/" \
72  f"{self.api_config.project_id}/merge_requests/" \
73  f"{self.api_config.mr_iid}/changes"
74  headers = {'Private-Token': self.api_config.api_token}
75  path_key = "new_path"
76  change_key = "diff"
77  elif self.api_config.running_on == Runner.GITHUB:
78  api_req_url = f"{self.api_config.api_url}/repos/" \
79  f"{self.api_config.github_repo_slug}/pulls/" + \
80  f"{self.api_config.github_pull_request}/files"
81  headers = {
82  "Authorization": f"Bearer {self.api_config.api_token}",
83  "X-GitHub-Api-Version": "2022-11-28",
84  "Accept": "application/vnd.github+json"
85  }
86  path_key = "filename"
87  change_key = "patch"
88  else:
89  api_req_url = "https://api.github.com/repos/" \
90  f"{self.api_config.travis_repo_slug}/pulls/" \
91  f"{self.api_config.travis_pull_request}/files"
92  headers = {}
93  path_key = "filename"
94  change_key = "patch"
95 
96  context = ssl.create_default_context()
97  context.check_hostname = False
98  context.verify_mode = ssl.CERT_NONE
99 
100  req = urllib.request.Request(api_req_url, headers=headers)
101  try:
102  with urllib.request.urlopen(req, context=context) as response:
103  change_response = response.read()
104  except Exception as e:
105  print(f"Unable to get URL {api_req_url}")
106  raise e
107 
108  change_response = json.loads(change_response)
109  if self.api_config.running_on == Runner.GITLAB:
110  changes = change_response['changes']
111  else:
112  changes = change_response
113 
114  remove_diff_regex = re.compile(r"^([ +-])(.*)$", re.MULTILINE)
115 
116  for change in changes:
117  if path_key in change and change_key in change:
118  path_to_be_excluded = self.__is_excluded_path__is_excluded_path(change[path_key])
119  if path_to_be_excluded is False:
120  curr_file = os.path.join(self.temp_dir.name, change[path_key])
121  curr_dir = os.path.dirname(curr_file)
122  if curr_dir != self.temp_dir.name:
123  os.makedirs(name=curr_dir, exist_ok=True)
124  curr_file = open(file=curr_file, mode='w+', encoding='UTF-8')
125  print(re.sub(remove_diff_regex, r"\2", change[change_key]),
126  file=curr_file)
127 
128  return self.temp_dir.name
bool __is_excluded_path(self, str path)
Definition: RepoSetup.py:48
def __init__(self, CliOptions cli_options, ApiConfig api_config)
Definition: RepoSetup.py:30