Coverage for jaypore_ci/interfaces.py: 82%
72 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-30 09:04 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-30 09:04 +0000
1"""
2Defines interfaces for remotes and executors.
4Currently only gitea and docker are supported as remote and executor
5respectively.
6"""
7from enum import Enum
8from pathlib import Path
9from urllib.parse import urlparse
10from typing import NamedTuple, List
13class TriggerFailed(Exception):
14 "Failure to trigger a job"
17class RemoteApiFailed(Exception):
18 "Failure while working with a remote"
21class JobStatus(NamedTuple):
22 is_running: bool
23 exit_code: int
24 logs: str
25 started_at: str
26 finished_at: str
29class Status(Enum):
30 "Each pipeline can ONLY be in any one of these statuses"
31 PENDING = 10
32 RUNNING = 30
33 FAILED = 40
34 PASSED = 50
35 TIMEOUT = 60
36 SKIPPED = 70
39class RemoteInfo(NamedTuple):
40 """
41 Holds information about the remote irrespective of if the remote was ssh or
42 https.
43 """
45 netloc: str
46 owner: str
47 repo: str
48 original: str
50 @classmethod
51 def parse(cls, remote: str) -> "RemoteInfo":
52 """
53 Given a git remote url string, parses and breaks down information
54 contained in the url.
56 Works with the following formats:
58 ssh://git@gitea.arjoonn.com:arjoonn/jaypore_ci.git
59 ssh+git://git@gitea.arjoonn.com:arjoonn/jaypore_ci.git
61 git@gitea.arjoonn.com:arjoonn/jaypore_ci.git
62 git@gitea.arjoonn.com:arjoonn/jaypore_ci.git
64 https://gitea.arjoonn.com/midpath/jaypore_ci.git
65 http://gitea.arjoonn.com/midpath/jaypore_ci.git
66 """
67 original = remote
68 if ( 68 ↛ 73line 68 didn't jump to line 73
69 ("ssh://" in remote or "ssh+git://" in remote or "://" not in remote)
70 and "@" in remote
71 and remote.endswith(".git")
72 ):
73 _, remote = remote.split("@")
74 netloc, path = remote.split(":")
75 owner, repo = path.split("/")
76 return RemoteInfo(
77 netloc=netloc,
78 owner=owner,
79 repo=repo.replace(".git", ""),
80 original=original,
81 )
82 url = urlparse(remote)
83 return RemoteInfo(
84 netloc=url.netloc,
85 owner=Path(url.path).parts[1],
86 repo=Path(url.path).parts[2].replace(".git", ""),
87 original=original,
88 )
91class Repo:
92 """
93 Contains information about the current VCS repo.
94 """
96 def __init__(self, sha: str, branch: str, remote: str, commit_message: str):
97 self.sha: str = sha
98 self.branch: str = branch
99 self.remote: str = remote
100 self.commit_message: str = commit_message
102 def files_changed(self, target: str) -> List[str]:
103 """
104 Returns list of file paths that have changed between current sha and
105 target.
106 """
107 raise NotImplementedError()
109 @classmethod
110 def from_env(cls) -> "Repo":
111 """
112 Creates a :class:`~jaypore_ci.interfaces.Repo` instance
113 from the environment and git repo on disk.
114 """
115 raise NotImplementedError()
118class Executor:
119 """
120 An executor is something used to run a job.
121 It could be docker / podman / shell etc.
122 """
124 def run(self, job: "Job") -> str:
125 "Run a job and return it's ID"
126 raise NotImplementedError()
128 def __init__(self):
129 self.pipe_id = None
130 self.pipeline = None
132 def set_pipeline(self, pipeline: "Pipeline") -> None:
133 """Set the current pipeline to the given one."""
134 self.pipe_id = id(pipeline)
135 self.pipeline = pipeline
137 def setup(self) -> None:
138 """
139 This function is meant to perform any work that should be done before
140 running any jobs.
141 """
143 def teardown(self) -> None:
144 """
145 On exit the executor must clean up any pending / stuck / zombie jobs that are still there.
146 """
148 def get_status(self, run_id: str) -> JobStatus:
149 """
150 Returns the status of a given run.
151 """
152 raise NotImplementedError()
155class Remote:
156 """
157 Something that allows us to show other people the status of the CI job.
158 It could be gitea / github / gitlab / email system.
159 """
161 def __init__(self, *, sha, branch):
162 self.sha = sha
163 self.branch = branch
165 def publish(self, report: str, status: str):
166 """
167 Publish this report somewhere.
168 """
169 raise NotImplementedError()
171 def setup(self) -> None:
172 """
173 This function is meant to perform any work that should be done before
174 running any jobs.
175 """
177 def teardown(self) -> None:
178 """
179 This function will be called once the pipeline is finished.
180 """
182 @classmethod
183 def from_env(cls, *, repo: "Repo"):
184 """
185 This function should create a Remote instance from the given environment.
186 It can read git information / look at environment variables etc.
187 """
188 raise NotImplementedError()
191class Reporter:
192 """
193 Something that generates the status of a pipeline.
195 It can be used to generate reports in markdown, plaintext, html, pdf etc.
196 """
198 def render(self, pipeline: "Pipeline") -> str:
199 """
200 Render a report for the pipeline.
201 """
202 raise NotImplementedError()