primitive 0.1.79__py3-none-any.whl → 0.1.81__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
primitive/__about__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2024-present Dylan Stein <dylan@primitive.tech>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- __version__ = "0.1.79"
4
+ __version__ = "0.1.81"
@@ -138,8 +138,7 @@ class Agent(BaseAction):
138
138
  runner = AgentRunner(
139
139
  primitive=self.primitive,
140
140
  source_dir=source_dir,
141
- job_id=job_run["id"],
142
- job_slug=job_run["job"]["slug"],
141
+ job_run=job_run,
143
142
  max_log_size=500 * 1024,
144
143
  )
145
144
  except Exception as e:
@@ -24,6 +24,7 @@ class Process:
24
24
  self.stdout_thread = None
25
25
  self.stderr_thread = None
26
26
  self._errors = 0
27
+ self._warnings = 0
27
28
 
28
29
  def start(self):
29
30
  # Start the process
@@ -53,6 +54,7 @@ class Process:
53
54
  self._errors += 1
54
55
  elif "warning" in raw_data.lower():
55
56
  logger.warning(raw_data)
57
+ self._warnings += 1
56
58
  else:
57
59
  logger.info(raw_data)
58
60
  elif key.fileobj is self.process.stderr:
@@ -117,3 +119,7 @@ class Process:
117
119
  @property
118
120
  def errors(self) -> int:
119
121
  return self._errors
122
+
123
+ @property
124
+ def warnings(self) -> int:
125
+ return self._warnings
primitive/agent/runner.py CHANGED
@@ -4,6 +4,7 @@ import typing
4
4
  from pathlib import Path, PurePath
5
5
  from time import sleep
6
6
  from typing import Dict, Iterable, List, Optional, TypedDict, Callable
7
+ from enum import IntEnum
7
8
 
8
9
  import yaml
9
10
  from loguru import logger
@@ -39,22 +40,29 @@ class JobDescription(TypedDict):
39
40
  steps: List[JobStep]
40
41
 
41
42
 
43
+ # NOTE This must match FailureLevel subclass in JobSettings model
44
+ class FailureLevel(IntEnum):
45
+ ERROR = 1
46
+ WARNING = 2
47
+
48
+
42
49
  class AgentRunner:
43
50
  def __init__(
44
51
  self,
45
52
  primitive: "primitive.client.Primitive",
46
53
  source_dir: Path,
47
- job_id: str,
48
- job_slug: str,
54
+ job_run: Dict,
49
55
  max_log_size: int = 10 * 1024 * 1024,
50
56
  log_to_file: bool = True,
51
57
  ) -> None:
52
58
  self.primitive = primitive
53
59
  self.source_dir = source_dir
54
60
  self.workdir = "."
55
- self.job_id = job_id
56
- self.job_slug = job_slug
61
+ self.job_id = job_run["id"]
62
+ self.job_slug = job_run["job"]["slug"]
57
63
  self.max_log_size = max_log_size
64
+ self.parse_logs = job_run["jobSettings"]["parseLogs"]
65
+ self.failure_level = job_run["jobSettings"]["failureLevel"]
58
66
  self.log_to_file = log_to_file
59
67
 
60
68
  # Enable and configure logger
@@ -140,7 +148,8 @@ class AgentRunner:
140
148
  logger.error(f"{self.job_slug} concluded with error(s)")
141
149
  return
142
150
 
143
- total_job_errors = 0
151
+ fail_level_detected = False
152
+ total_parsed_levels = {FailureLevel.ERROR: 0, FailureLevel.WARNING: 0}
144
153
  for step in self.steps():
145
154
  logger.info(f"Beginning step {step['name']}")
146
155
 
@@ -183,7 +192,16 @@ class AgentRunner:
183
192
  status_thread.start()
184
193
 
185
194
  returncode = proc.wait()
186
- total_job_errors += proc.errors
195
+
196
+ if proc.errors > 0 and self.failure_level >= FailureLevel.ERROR:
197
+ fail_level_detected = True
198
+
199
+ if proc.warnings > 0 and self.failure_level >= FailureLevel.WARNING:
200
+ fail_level_detected = True
201
+
202
+ total_parsed_levels[FailureLevel.ERROR] += proc.errors
203
+ total_parsed_levels[FailureLevel.WARNING] += proc.warnings
204
+
187
205
  status_thread.join()
188
206
 
189
207
  self.collect_artifacts(step)
@@ -194,14 +212,20 @@ class AgentRunner:
194
212
  )
195
213
  logger.error(f"{self.job_slug} concluded with error(s)")
196
214
  return
197
-
198
- # TODO: Remove this for now until we have a setting to enable log parsing
199
- # if total_job_errors > 0:
200
- # self.primitive.jobs.job_run_update(
201
- # self.job_id, status="request_completed", conclusion="failure"
202
- # )
203
- # logger.error(f"{self.job_slug} concluded with error(s)")
204
- # return
215
+
216
+ if fail_level_detected and self.parse_logs:
217
+ self.primitive.jobs.job_run_update(
218
+ self.job_id, status="request_completed", conclusion="failure"
219
+ )
220
+
221
+ logger.error(
222
+ (
223
+ f"{self.job_slug} concluded"
224
+ f" with {total_parsed_levels[FailureLevel.ERROR]} error(s)"
225
+ f" and {total_parsed_levels[FailureLevel.WARNING]} warning(s)"
226
+ )
227
+ )
228
+ return
205
229
 
206
230
  self.primitive.jobs.job_run_update(
207
231
  self.job_id, status="request_completed", conclusion="success"
primitive/git/actions.py CHANGED
@@ -1,5 +1,5 @@
1
- import os
2
1
  from pathlib import Path
2
+ from subprocess import run, CalledProcessError, DEVNULL
3
3
 
4
4
  from gql import gql
5
5
  from loguru import logger
@@ -31,14 +31,31 @@ class Git(BaseAction):
31
31
  destination: Path = Path.cwd(),
32
32
  ) -> Path:
33
33
  logger.debug(f"Downloading source code from {git_repo_full_name} {git_ref}")
34
- # TODO: switch to subprocess.run or subprocess.Popen
35
- url = f"https://api.github.com/repos/{git_repo_full_name}/tarball/{git_ref}"
36
- untar_dir = Path(destination).joinpath(git_repo_full_name.split("/")[-1])
37
- untar_dir.mkdir(parents=True, exist_ok=True)
38
34
 
39
- result = os.system(
40
- f"curl -s -L -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer {github_access_token}' -H 'X-GitHub-Api-Version: 2022-11-28' {url} | tar zx --strip-components 1 -C {untar_dir}"
35
+ url = (
36
+ f"https://oauth2:{github_access_token}@github.com/{git_repo_full_name}.git"
41
37
  )
42
- if result != 0:
38
+ source_dir = Path(destination).joinpath(git_repo_full_name.split("/")[-1])
39
+
40
+ try:
41
+ run(
42
+ ["git", "clone", url, source_dir, "--no-checkout"],
43
+ check=True,
44
+ stdout=DEVNULL,
45
+ stderr=DEVNULL,
46
+ )
47
+ except CalledProcessError:
43
48
  raise Exception("Failed to download repository")
44
- return untar_dir
49
+
50
+ try:
51
+ run(
52
+ ["git", "checkout", git_ref],
53
+ check=True,
54
+ cwd=source_dir,
55
+ stdout=DEVNULL,
56
+ stderr=DEVNULL,
57
+ )
58
+ except CalledProcessError:
59
+ raise Exception("Failed to checkout ref")
60
+
61
+ return source_dir
@@ -30,6 +30,8 @@ fragment JobRunFragment on JobRun {
30
30
  jobSettings {
31
31
  containerArgs
32
32
  rootDirectory
33
+ parseLogs
34
+ failureLevel
33
35
  }
34
36
  gitCommit {
35
37
  sha
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: primitive
3
- Version: 0.1.79
3
+ Version: 0.1.81
4
4
  Project-URL: Documentation, https://github.com//primitivecorp/primitive-cli#readme
5
5
  Project-URL: Issues, https://github.com//primitivecorp/primitive-cli/issues
6
6
  Project-URL: Source, https://github.com//primitivecorp/primitive-cli
@@ -1,13 +1,13 @@
1
- primitive/__about__.py,sha256=vzO4WHOLXOFAvlTZ3lOnqtNHo1EekGFzz-ZQ6TeqQ8k,130
1
+ primitive/__about__.py,sha256=huocY9XCDVB1AbopYm7klrVTheuItyqQL8-9KeAP9cA,130
2
2
  primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
3
3
  primitive/cli.py,sha256=CiI60bG3UZyNFuLTpchr0KeJRG5SALj455Ob11CegGE,2412
4
4
  primitive/client.py,sha256=PPyIQRvKKSqCF9RRF5mJJ4Vqqolpzy1YXqffNLKIvAA,2390
5
5
  primitive/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- primitive/agent/actions.py,sha256=Hosy2o2FntfBtcNqqHuMFq9dm99EVfySy0v2JGeufvc,6474
6
+ primitive/agent/actions.py,sha256=YUlpi4VCQQTMpoNwDg9meW4liWtdzXCweEm9gD8MXYw,6408
7
7
  primitive/agent/commands.py,sha256=-dVDilELfkGfbZB7qfEPs77Dm1oT62qJj4tsIk4KoxI,254
8
- primitive/agent/process.py,sha256=4dpuO4cZg_SYi0kCoZJrm-ugB_mAnxYWaNbIyUHkoII,3395
8
+ primitive/agent/process.py,sha256=32eoj0W1-LG-9xxeHia-jk9jTah1cnmjCYnvczgXYGU,3538
9
9
  primitive/agent/provision.py,sha256=rmwnro1K5F8mwtd45XAq7RVQmpDWnbBCQ8X_qgWhm3M,1546
10
- primitive/agent/runner.py,sha256=XOOtAcMpngv9qbBGCZyEvVsFgI3gt5n5xTCcgVV5ceM,8301
10
+ primitive/agent/runner.py,sha256=2xGv_Lcr536RjJySC4fX8MxAb4yF8IywHC047VKAfuM,9168
11
11
  primitive/agent/uploader.py,sha256=OkgwXhWKoECOJnW_ZmpzmUS_cpb-orC_uebNcmf5byw,2948
12
12
  primitive/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  primitive/auth/actions.py,sha256=MPsG9LcKcOPwA7gZ9Ewk0PZJhTQvIrGfODdz4GxSzgA,999
@@ -31,7 +31,7 @@ primitive/files/graphql/fragments.py,sha256=II6WHZjzSqX4IELwdiWokqHTKvDq6mMHF5gp
31
31
  primitive/files/graphql/mutations.py,sha256=Da_e6WSp-fsCYVE9A6SGkIQy9WDzjeQycNyHEn7vJqE,935
32
32
  primitive/files/graphql/queries.py,sha256=_ky-IRz928sKeSJuqaggTPxV4CGgmho3OyaAFu1z7nw,397
33
33
  primitive/git/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- primitive/git/actions.py,sha256=0KHeHViZZqIhF6-Eqvhs0g_UmglqyWrOQKElQCm6jVw,1506
34
+ primitive/git/actions.py,sha256=x06CI0sR9sIp23CHpmyovTaoRKseTlTrlpKTvF39VTs,1747
35
35
  primitive/git/commands.py,sha256=sCeSjkRgSEjCEsB5seXgB_h6xfk0KpvMvzMKoRfUbRA,1177
36
36
  primitive/git/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  primitive/git/graphql/queries.py,sha256=I1HGlqBb1lHIAWVSsC8tVY9JdsQ8DJVqs4nqSTcL30M,98
@@ -50,7 +50,7 @@ primitive/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  primitive/jobs/actions.py,sha256=CtyO-Z9614TgIoXJJX1QGsoll0fgpBIjG9PJH5JwCQs,4901
51
51
  primitive/jobs/commands.py,sha256=MxPCkBEYW_eLNqgCRYeyj7ZcLOFAWfpVZlqDR2Y_S0o,830
52
52
  primitive/jobs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
- primitive/jobs/graphql/fragments.py,sha256=xtT168P-ChEj3UhSXxFiYPgYuMDyey9bXYkk-TtM3a4,542
53
+ primitive/jobs/graphql/fragments.py,sha256=GZ_rVc_pc3MfC8EhCY_X9rjeNUdiwEytdqrknHYWO-E,573
54
54
  primitive/jobs/graphql/mutations.py,sha256=8ASvCmwQh7cMeeiykOdYaYVryG8FRIuVF6v_J8JJZuw,219
55
55
  primitive/jobs/graphql/queries.py,sha256=BrU_GnLjK0bTAmWsLSmGEUea7EM8MqTKxN1Qp6sSjwc,1597
56
56
  primitive/organizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -90,8 +90,8 @@ primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIU
90
90
  primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
91
91
  primitive/utils/shell.py,sha256=j7E1YwgNWw57dFHVfEbqRNVcPHX0xDefX2vFSNgeI_8,1648
92
92
  primitive/utils/verible.py,sha256=Zb5NUISvcaIgEvgCDBWr-GCoceMa79Tcwvr5Wl9lfnA,2252
93
- primitive-0.1.79.dist-info/METADATA,sha256=B8RbreK13SAPo8mg6_qfIy2p41H6dm5tKKBdM4Vmzso,3642
94
- primitive-0.1.79.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
95
- primitive-0.1.79.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
96
- primitive-0.1.79.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
97
- primitive-0.1.79.dist-info/RECORD,,
93
+ primitive-0.1.81.dist-info/METADATA,sha256=NZ5uyQN0JCEnVE3egmqdlqIUM1ScD6Wk9NTLkqoEcFY,3642
94
+ primitive-0.1.81.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
95
+ primitive-0.1.81.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
96
+ primitive-0.1.81.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
97
+ primitive-0.1.81.dist-info/RECORD,,