primer.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import logging
  2. from pathlib import Path
  3. from typing import Dict, List, Optional, Union
  4. import git
  5. PRIMER_DIRECTORY_PATH = Path(".pylint_primer_tests")
  6. class PackageToLint:
  7. """Represents data about a package to be tested during primer tests"""
  8. url: str
  9. """URL of the repository to clone"""
  10. branch: str
  11. """Branch of the repository to clone"""
  12. directories: List[str]
  13. """Directories within the repository to run pylint over"""
  14. commit: Optional[str]
  15. """Commit hash to pin the repository on"""
  16. pylint_additional_args: List[str]
  17. """Arguments to give to pylint"""
  18. pylintrc_relpath: Optional[str]
  19. """Path relative to project's main directory to the pylintrc if it exists"""
  20. def __init__(
  21. self,
  22. url: str,
  23. branch: str,
  24. directories: List[str],
  25. commit: Optional[str] = None,
  26. pylint_additional_args: Optional[List[str]] = None,
  27. pylintrc_relpath: Optional[str] = None,
  28. ) -> None:
  29. self.url = url
  30. self.branch = branch
  31. self.directories = directories
  32. self.commit = commit
  33. self.pylint_additional_args = pylint_additional_args or []
  34. self.pylintrc_relpath = pylintrc_relpath
  35. @property
  36. def pylintrc(self) -> Optional[Path]:
  37. if self.pylintrc_relpath is None:
  38. return None
  39. return self.clone_directory / self.pylintrc_relpath
  40. @property
  41. def clone_directory(self) -> Path:
  42. """Directory to clone repository into"""
  43. clone_name = "/".join(self.url.split("/")[-2:]).replace(".git", "")
  44. return PRIMER_DIRECTORY_PATH / clone_name
  45. @property
  46. def paths_to_lint(self) -> List[str]:
  47. """The paths we need to lint"""
  48. return [str(self.clone_directory / path) for path in self.directories]
  49. @property
  50. def pylint_args(self) -> List[str]:
  51. options: List[str] = []
  52. if self.pylintrc is not None:
  53. # There is an error if rcfile is given but does not exists
  54. options += [f"--rcfile={self.pylintrc}"]
  55. return self.paths_to_lint + options + self.pylint_additional_args
  56. def lazy_clone(self) -> None: # pragma: no cover
  57. """Concatenates the target directory and clones the file
  58. Not expected to be tested as the primer won't work if it doesn't.
  59. It's tested in the continuous integration primers, only the coverage
  60. is not calculated on everything. If lazy clone breaks for local use
  61. we'll probably notice because we'll have a fatal when launching the
  62. primer locally.
  63. """
  64. logging.info("Lazy cloning %s", self.url)
  65. if not self.clone_directory.exists():
  66. options: Dict[str, Union[str, int]] = {
  67. "url": self.url,
  68. "to_path": str(self.clone_directory),
  69. "branch": self.branch,
  70. "depth": 1,
  71. }
  72. logging.info("Directory does not exists, cloning: %s", options)
  73. git.Repo.clone_from(**options)
  74. return
  75. remote_sha1_commit = (
  76. git.cmd.Git().ls_remote(self.url, self.branch).split("\t")[0]
  77. )
  78. local_sha1_commit = git.Repo(self.clone_directory).head.object.hexsha
  79. if remote_sha1_commit != local_sha1_commit:
  80. logging.info(
  81. "Remote sha is '%s' while local sha is '%s': pulling new commits",
  82. remote_sha1_commit,
  83. local_sha1_commit,
  84. )
  85. repo = git.Repo(self.clone_directory)
  86. origin = repo.remotes.origin
  87. origin.pull()
  88. else:
  89. logging.info("Repository already up to date.")