primitive 0.1.12__py3-none-any.whl → 0.1.14__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 +1 -1
- primitive/agent/actions.py +4 -4
- primitive/cli.py +8 -0
- primitive/client.py +6 -0
- primitive/daemons/actions.py +75 -0
- primitive/daemons/commands.py +65 -0
- primitive/daemons/launch_agents.py +144 -0
- primitive/daemons/launch_service.py +170 -0
- primitive/jobs/actions.py +303 -0
- primitive/jobs/commands.py +41 -0
- primitive/organizations/actions.py +84 -0
- primitive/organizations/commands.py +24 -0
- primitive/projects/actions.py +52 -148
- primitive/projects/commands.py +24 -0
- {primitive-0.1.12.dist-info → primitive-0.1.14.dist-info}/METADATA +1 -1
- {primitive-0.1.12.dist-info → primitive-0.1.14.dist-info}/RECORD +19 -10
- {primitive-0.1.12.dist-info → primitive-0.1.14.dist-info}/WHEEL +0 -0
- {primitive-0.1.12.dist-info → primitive-0.1.14.dist-info}/entry_points.txt +0 -0
- {primitive-0.1.12.dist-info → primitive-0.1.14.dist-info}/licenses/LICENSE.txt +0 -0
primitive/__about__.py
CHANGED
primitive/agent/actions.py
CHANGED
@@ -32,7 +32,7 @@ class Agent(BaseAction):
|
|
32
32
|
sleep(5)
|
33
33
|
continue
|
34
34
|
|
35
|
-
job_runs_data = self.primitive.
|
35
|
+
job_runs_data = self.primitive.jobs.get_job_runs(
|
36
36
|
status="pending", first=1, reservation_id=active_reservation_id
|
37
37
|
)
|
38
38
|
|
@@ -52,7 +52,7 @@ class Agent(BaseAction):
|
|
52
52
|
)
|
53
53
|
|
54
54
|
github_access_token = (
|
55
|
-
self.primitive.
|
55
|
+
self.primitive.jobs.github_access_token_for_job_run(
|
56
56
|
job_run["id"]
|
57
57
|
)
|
58
58
|
)
|
@@ -68,7 +68,7 @@ class Agent(BaseAction):
|
|
68
68
|
if job_run["job"]["slug"] == "lint":
|
69
69
|
logger.debug("Executing Lint Job")
|
70
70
|
|
71
|
-
self.primitive.
|
71
|
+
self.primitive.jobs.job_run_update(
|
72
72
|
job_run["id"], status="request_in_progress"
|
73
73
|
)
|
74
74
|
|
@@ -79,7 +79,7 @@ class Agent(BaseAction):
|
|
79
79
|
conclusion = "success"
|
80
80
|
else:
|
81
81
|
conclusion = "failure"
|
82
|
-
self.primitive.
|
82
|
+
self.primitive.jobs.job_run_update(
|
83
83
|
job_run["id"],
|
84
84
|
status="request_completed",
|
85
85
|
conclusion=conclusion,
|
primitive/cli.py
CHANGED
@@ -9,6 +9,10 @@ from .hardware.commands import cli as hardware_commands
|
|
9
9
|
from .lint.commands import cli as lint_commands
|
10
10
|
from .agent.commands import cli as agent_commands
|
11
11
|
from .git.commands import cli as git_commands
|
12
|
+
from .daemons.commands import cli as daemons_commands
|
13
|
+
from .jobs.commands import cli as jobs_commands
|
14
|
+
from .organizations.commands import cli as organizations_commands
|
15
|
+
from .projects.commands import cli as projects_commands
|
12
16
|
|
13
17
|
|
14
18
|
@click.group()
|
@@ -59,6 +63,10 @@ cli.add_command(hardware_commands, "hardware")
|
|
59
63
|
cli.add_command(lint_commands, "lint")
|
60
64
|
cli.add_command(agent_commands, "agent")
|
61
65
|
cli.add_command(git_commands, "git")
|
66
|
+
cli.add_command(daemons_commands, "daemons")
|
67
|
+
cli.add_command(jobs_commands, "jobs")
|
68
|
+
cli.add_command(organizations_commands, "organizations")
|
69
|
+
cli.add_command(projects_commands, "projects")
|
62
70
|
|
63
71
|
if __name__ == "__main__":
|
64
72
|
cli(obj={})
|
primitive/client.py
CHANGED
@@ -9,6 +9,9 @@ from .hardware.actions import Hardware
|
|
9
9
|
from .lint.actions import Lint
|
10
10
|
from .agent.actions import Agent
|
11
11
|
from .git.actions import Git
|
12
|
+
from .daemons.actions import Daemons
|
13
|
+
from .jobs.actions import Jobs
|
14
|
+
from .organizations.actions import Organizations
|
12
15
|
|
13
16
|
from loguru import logger
|
14
17
|
|
@@ -54,13 +57,16 @@ class Primitive:
|
|
54
57
|
)
|
55
58
|
|
56
59
|
self.auth: Auth = Auth(self)
|
60
|
+
self.organizations: Organizations = Organizations(self)
|
57
61
|
self.projects: Projects = Projects(self)
|
62
|
+
self.jobs: Jobs = Jobs(self)
|
58
63
|
self.files: Files = Files(self)
|
59
64
|
self.simulations: Simulations = Simulations(self)
|
60
65
|
self.hardware: Hardware = Hardware(self)
|
61
66
|
self.lint: Lint = Lint(self)
|
62
67
|
self.agent: Agent = Agent(self)
|
63
68
|
self.git: Git = Git(self)
|
69
|
+
self.daemons: Daemons = Daemons(self)
|
64
70
|
|
65
71
|
def get_host_config(self):
|
66
72
|
self.full_config = read_config_file()
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import platform
|
2
|
+
import typing
|
3
|
+
|
4
|
+
if typing.TYPE_CHECKING:
|
5
|
+
from ..client import Primitive
|
6
|
+
|
7
|
+
from .launch_agents import (
|
8
|
+
full_launch_agent_install,
|
9
|
+
full_launch_agent_uninstall,
|
10
|
+
start_launch_agent,
|
11
|
+
stop_launch_agent,
|
12
|
+
view_launch_agent_logs,
|
13
|
+
)
|
14
|
+
|
15
|
+
from .launch_service import (
|
16
|
+
full_service_install,
|
17
|
+
full_service_uninstall,
|
18
|
+
start_service,
|
19
|
+
stop_service,
|
20
|
+
view_service_logs,
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
class Daemons:
|
25
|
+
def __init__(self, primitive) -> None:
|
26
|
+
self.primitive: Primitive = primitive
|
27
|
+
self.os_family = platform.system()
|
28
|
+
|
29
|
+
def install(self):
|
30
|
+
result = True
|
31
|
+
if self.os_family == "Darwin":
|
32
|
+
full_launch_agent_install()
|
33
|
+
elif self.os_family == "Linux":
|
34
|
+
full_service_install()
|
35
|
+
elif self.os_family == "Windows":
|
36
|
+
print("Not Implemented")
|
37
|
+
return result
|
38
|
+
|
39
|
+
def uninstall(self):
|
40
|
+
result = True
|
41
|
+
if self.os_family == "Darwin":
|
42
|
+
full_launch_agent_uninstall()
|
43
|
+
elif self.os_family == "Linux":
|
44
|
+
full_service_uninstall()
|
45
|
+
elif self.os_family == "Windows":
|
46
|
+
print("Not Implemented")
|
47
|
+
return result
|
48
|
+
|
49
|
+
def stop(self) -> bool:
|
50
|
+
result = True
|
51
|
+
if self.os_family == "Darwin":
|
52
|
+
result = stop_launch_agent()
|
53
|
+
elif self.os_family == "Linux":
|
54
|
+
stop_service()
|
55
|
+
elif self.os_family == "Windows":
|
56
|
+
print("Not Implemented")
|
57
|
+
return result
|
58
|
+
|
59
|
+
def start(self) -> bool:
|
60
|
+
result = True
|
61
|
+
if self.os_family == "Darwin":
|
62
|
+
result = start_launch_agent()
|
63
|
+
elif self.os_family == "Linux":
|
64
|
+
start_service()
|
65
|
+
elif self.os_family == "Windows":
|
66
|
+
print("Not Implemented")
|
67
|
+
return result
|
68
|
+
|
69
|
+
def logs(self):
|
70
|
+
if self.os_family == "Darwin":
|
71
|
+
view_launch_agent_logs()
|
72
|
+
elif self.os_family == "Linux":
|
73
|
+
view_service_logs()
|
74
|
+
elif self.os_family == "Windows":
|
75
|
+
print("Not Implemented")
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from ..utils.printer import print_result
|
4
|
+
import typing
|
5
|
+
|
6
|
+
if typing.TYPE_CHECKING:
|
7
|
+
from ..client import Primitive
|
8
|
+
|
9
|
+
|
10
|
+
@click.group()
|
11
|
+
@click.pass_context
|
12
|
+
def cli(context):
|
13
|
+
"""Daemon"""
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
17
|
+
@cli.command("install")
|
18
|
+
@click.pass_context
|
19
|
+
def install_daemon_command(context):
|
20
|
+
"""Install the full primitive daemon"""
|
21
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
22
|
+
result = primitive.daemons.install()
|
23
|
+
print_result(message=result, context=context)
|
24
|
+
|
25
|
+
|
26
|
+
@cli.command("uninstall")
|
27
|
+
@click.pass_context
|
28
|
+
def uninstall_daemon_command(context):
|
29
|
+
"""Uninstall the full primitive Daemon"""
|
30
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
31
|
+
result = primitive.daemons.uninstall()
|
32
|
+
print_result(message=result, context=context)
|
33
|
+
|
34
|
+
|
35
|
+
@cli.command("stop")
|
36
|
+
@click.pass_context
|
37
|
+
def stop_daemon_command(context):
|
38
|
+
"""Stop primitive Daemon"""
|
39
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
40
|
+
result = primitive.daemons.stop()
|
41
|
+
message = "stopping primitive daemon"
|
42
|
+
if context.obj["JSON"]:
|
43
|
+
message = result
|
44
|
+
print_result(message=message, context=context)
|
45
|
+
|
46
|
+
|
47
|
+
@cli.command("start")
|
48
|
+
@click.pass_context
|
49
|
+
def start_daemon_command(context):
|
50
|
+
"""Start primitive Daemon"""
|
51
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
52
|
+
result = primitive.daemons.start()
|
53
|
+
message = "starting primitive daemon"
|
54
|
+
if context.obj["JSON"]:
|
55
|
+
message = result
|
56
|
+
print_result(message=message, context=context)
|
57
|
+
|
58
|
+
|
59
|
+
@cli.command("logs")
|
60
|
+
@click.pass_context
|
61
|
+
def log_daemon_command(context):
|
62
|
+
"""Logs from primitive Daemon"""
|
63
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
64
|
+
result = primitive.daemons.logs()
|
65
|
+
print_result(message=result, context=context)
|
@@ -0,0 +1,144 @@
|
|
1
|
+
import os
|
2
|
+
from pathlib import Path
|
3
|
+
import subprocess
|
4
|
+
|
5
|
+
HOME_DIRECTORY = Path.home()
|
6
|
+
CURRENT_USER = str(HOME_DIRECTORY.expanduser()).lstrip("/Users/")
|
7
|
+
|
8
|
+
PRIMITIVE_BINARY_PATH = Path(HOME_DIRECTORY / ".pyenv" / "shims" / "primitive")
|
9
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH = Path(
|
10
|
+
HOME_DIRECTORY / "Library" / "LaunchAgents" / "tech.primitive.agent.plist"
|
11
|
+
)
|
12
|
+
PRIMITIVE_LAUNCH_AGENT_LOGS = Path(
|
13
|
+
HOME_DIRECTORY / "Library" / "Logs" / "tech.primitive.agent.log"
|
14
|
+
)
|
15
|
+
PRIMITIVE_LAUNCH_AGENT_LABEL = "tech.primitive.agent"
|
16
|
+
PRIMITIVE_LAUNCH_AGENT_WORKING_DIR = Path(
|
17
|
+
HOME_DIRECTORY / "Logs" / "tech.primitive.agent.log"
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
def stop_launch_agent():
|
22
|
+
try:
|
23
|
+
stop_existing_process = f"launchctl stop {PRIMITIVE_LAUNCH_AGENT_LABEL}"
|
24
|
+
subprocess.check_output(stop_existing_process.split(" "))
|
25
|
+
return True
|
26
|
+
except subprocess.CalledProcessError as exception:
|
27
|
+
print("stop_launch_agent: ", exception)
|
28
|
+
return False
|
29
|
+
|
30
|
+
|
31
|
+
def start_launch_agent():
|
32
|
+
try:
|
33
|
+
start_new_agent = f"launchctl start {PRIMITIVE_LAUNCH_AGENT_LABEL}"
|
34
|
+
subprocess.check_output(start_new_agent.split(" "))
|
35
|
+
return True
|
36
|
+
except subprocess.CalledProcessError as exception:
|
37
|
+
print("start_launch_agent: ", exception)
|
38
|
+
return False
|
39
|
+
|
40
|
+
|
41
|
+
def unload_launch_agent():
|
42
|
+
try:
|
43
|
+
remove_existing_agent = f"launchctl unload -w {PRIMITIVE_LAUNCH_AGENT_FILEPATH}"
|
44
|
+
subprocess.check_output(remove_existing_agent.split(" "))
|
45
|
+
return True
|
46
|
+
except subprocess.CalledProcessError as exception:
|
47
|
+
print("remove_launch_agent: ", exception)
|
48
|
+
return False
|
49
|
+
|
50
|
+
|
51
|
+
def load_launch_agent():
|
52
|
+
try:
|
53
|
+
load_new_plist = f"launchctl load -w {PRIMITIVE_LAUNCH_AGENT_FILEPATH}"
|
54
|
+
subprocess.check_output(load_new_plist.split(" "))
|
55
|
+
return True
|
56
|
+
except subprocess.CalledProcessError as exception:
|
57
|
+
print("load_launch_agent: ", exception)
|
58
|
+
return False
|
59
|
+
|
60
|
+
|
61
|
+
def create_stdout_file():
|
62
|
+
if not PRIMITIVE_LAUNCH_AGENT_LOGS.exists():
|
63
|
+
PRIMITIVE_LAUNCH_AGENT_LOGS.parent.mkdir(parents=True, exist_ok=True)
|
64
|
+
PRIMITIVE_LAUNCH_AGENT_LOGS.touch()
|
65
|
+
|
66
|
+
|
67
|
+
def delete_stdout_file():
|
68
|
+
if PRIMITIVE_LAUNCH_AGENT_LOGS.exists():
|
69
|
+
PRIMITIVE_LAUNCH_AGENT_LOGS.unlink()
|
70
|
+
|
71
|
+
|
72
|
+
def populate_fresh_launch_agent():
|
73
|
+
PRIMITIVE_LAUNCH_AGENT_LOGS.parent.mkdir(parents=True, exist_ok=True)
|
74
|
+
PRIMITIVE_LAUNCH_AGENT_LOGS.touch()
|
75
|
+
|
76
|
+
if PRIMITIVE_LAUNCH_AGENT_FILEPATH.exists():
|
77
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH.unlink()
|
78
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH.parent.mkdir(parents=True, exist_ok=True)
|
79
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH.touch()
|
80
|
+
|
81
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH.write_text(
|
82
|
+
f"""<?xml version="1.0" encoding="UTF-8"?>
|
83
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
84
|
+
<plist version="1.0">
|
85
|
+
<dict>
|
86
|
+
<key>KeepAlive</key>
|
87
|
+
<true/>
|
88
|
+
<key>Label</key>
|
89
|
+
<string>{PRIMITIVE_LAUNCH_AGENT_LABEL}</string>
|
90
|
+
<key>LimitLoadToSessionType</key>
|
91
|
+
<array>
|
92
|
+
<string>Aqua</string>
|
93
|
+
<string>Background</string>
|
94
|
+
<string>LoginWindow</string>
|
95
|
+
<string>StandardIO</string>
|
96
|
+
</array>
|
97
|
+
<key>ProgramArguments</key>
|
98
|
+
<array>
|
99
|
+
<string>{PRIMITIVE_BINARY_PATH}</string>
|
100
|
+
<string>agent</string>
|
101
|
+
</array>
|
102
|
+
<key>RunAtLoad</key>
|
103
|
+
<true/>
|
104
|
+
<key>StandardErrorPath</key>
|
105
|
+
<string>{PRIMITIVE_LAUNCH_AGENT_LOGS}</string>
|
106
|
+
<key>StandardOutPath</key>
|
107
|
+
<string>{PRIMITIVE_LAUNCH_AGENT_LOGS}</string>
|
108
|
+
</dict>
|
109
|
+
</plist>""" # noqa: E501
|
110
|
+
)
|
111
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH.chmod(0o644)
|
112
|
+
verify_launch_agent()
|
113
|
+
|
114
|
+
|
115
|
+
def verify_launch_agent():
|
116
|
+
plutil_check = f"plutil -lint {PRIMITIVE_LAUNCH_AGENT_FILEPATH}"
|
117
|
+
try:
|
118
|
+
subprocess.check_output(plutil_check.split(" "))
|
119
|
+
return True
|
120
|
+
except subprocess.CalledProcessError as exception:
|
121
|
+
print("verify_launch_agent: ", exception)
|
122
|
+
return False
|
123
|
+
|
124
|
+
|
125
|
+
def view_launch_agent_logs():
|
126
|
+
follow_logs = f"tail -f -n +1 {PRIMITIVE_LAUNCH_AGENT_LOGS}"
|
127
|
+
os.system(follow_logs)
|
128
|
+
|
129
|
+
|
130
|
+
def full_launch_agent_install():
|
131
|
+
stop_launch_agent()
|
132
|
+
unload_launch_agent()
|
133
|
+
populate_fresh_launch_agent()
|
134
|
+
create_stdout_file()
|
135
|
+
load_launch_agent()
|
136
|
+
start_launch_agent()
|
137
|
+
|
138
|
+
|
139
|
+
def full_launch_agent_uninstall():
|
140
|
+
stop_launch_agent()
|
141
|
+
unload_launch_agent()
|
142
|
+
if PRIMITIVE_LAUNCH_AGENT_FILEPATH.exists():
|
143
|
+
PRIMITIVE_LAUNCH_AGENT_FILEPATH.unlink()
|
144
|
+
delete_stdout_file()
|
@@ -0,0 +1,170 @@
|
|
1
|
+
import os
|
2
|
+
import configparser
|
3
|
+
import subprocess
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
HOME_DIRECTORY = Path.home()
|
7
|
+
|
8
|
+
PRIMITIVE_BINARY_PATH = Path(HOME_DIRECTORY / ".pyenv" / "shims" / "primitive")
|
9
|
+
|
10
|
+
PRIMITIVE_AGENT_SERVICE = "tech.primitive.agent.service"
|
11
|
+
PRIMITIVE_AGENT_LOGS = "tech.primitive.agent.log"
|
12
|
+
PRIMITIVE_AGENT_SERVICE_FILEPATH = Path(
|
13
|
+
HOME_DIRECTORY / ".config" / "systemd" / "user" / PRIMITIVE_AGENT_SERVICE
|
14
|
+
)
|
15
|
+
PRIMITIVE_AGENT_LOGS_FILEPATH = Path(
|
16
|
+
HOME_DIRECTORY / ".cache" / "primitive" / PRIMITIVE_AGENT_LOGS
|
17
|
+
)
|
18
|
+
|
19
|
+
|
20
|
+
def stop_service():
|
21
|
+
try:
|
22
|
+
if is_service_active():
|
23
|
+
stop_existing_service = f"systemctl --user stop {PRIMITIVE_AGENT_SERVICE}"
|
24
|
+
subprocess.check_output(stop_existing_service.split(" "))
|
25
|
+
return True
|
26
|
+
except subprocess.CalledProcessError as exception:
|
27
|
+
print("stop_service: ", exception)
|
28
|
+
return False
|
29
|
+
|
30
|
+
|
31
|
+
def is_service_active():
|
32
|
+
try:
|
33
|
+
is_service_active = (
|
34
|
+
f"systemctl --user show {PRIMITIVE_AGENT_SERVICE} -p ActiveState --value"
|
35
|
+
)
|
36
|
+
output = subprocess.check_output(is_service_active.split(" ")).decode().strip()
|
37
|
+
return output == "active"
|
38
|
+
except subprocess.CalledProcessError as exception:
|
39
|
+
print("is_service_active: ", exception)
|
40
|
+
return False
|
41
|
+
|
42
|
+
|
43
|
+
def disable_service():
|
44
|
+
try:
|
45
|
+
if is_service_enabled():
|
46
|
+
disable_existing_service = (
|
47
|
+
f"systemctl --user disable {PRIMITIVE_AGENT_SERVICE}"
|
48
|
+
)
|
49
|
+
subprocess.check_output(disable_existing_service.split(" "))
|
50
|
+
return True
|
51
|
+
except subprocess.CalledProcessError as exception:
|
52
|
+
print("disable_service: ", exception)
|
53
|
+
return False
|
54
|
+
|
55
|
+
|
56
|
+
def is_service_enabled():
|
57
|
+
try:
|
58
|
+
is_service_active = (
|
59
|
+
f"systemctl --user show {PRIMITIVE_AGENT_SERVICE} -p UnitFileState --value" # noqa
|
60
|
+
)
|
61
|
+
output = subprocess.check_output(is_service_active.split(" ")).decode().strip()
|
62
|
+
return output == "enabled"
|
63
|
+
except subprocess.CalledProcessError as exception:
|
64
|
+
print("is_service_enabled: ", exception)
|
65
|
+
return False
|
66
|
+
|
67
|
+
|
68
|
+
def populate_service_file():
|
69
|
+
PRIMITIVE_AGENT_LOGS_FILEPATH.parent.mkdir(parents=True, exist_ok=True)
|
70
|
+
PRIMITIVE_AGENT_LOGS_FILEPATH.touch()
|
71
|
+
|
72
|
+
if PRIMITIVE_AGENT_SERVICE_FILEPATH.exists():
|
73
|
+
PRIMITIVE_AGENT_SERVICE_FILEPATH.unlink()
|
74
|
+
PRIMITIVE_AGENT_SERVICE_FILEPATH.parent.mkdir(parents=True, exist_ok=True)
|
75
|
+
PRIMITIVE_AGENT_SERVICE_FILEPATH.touch()
|
76
|
+
|
77
|
+
config = configparser.ConfigParser()
|
78
|
+
config.optionxform = str # type: ignore
|
79
|
+
|
80
|
+
config["Unit"] = {
|
81
|
+
"Description": "Primitive Agent",
|
82
|
+
"After": "network.target",
|
83
|
+
}
|
84
|
+
|
85
|
+
config["Service"] = {
|
86
|
+
"ExecStart": f"{PRIMITIVE_BINARY_PATH} agent",
|
87
|
+
"Restart": "always",
|
88
|
+
"StandardError": f"append:{PRIMITIVE_AGENT_LOGS_FILEPATH}",
|
89
|
+
"StandardOutput": f"append:{PRIMITIVE_AGENT_LOGS_FILEPATH}",
|
90
|
+
}
|
91
|
+
|
92
|
+
config["Install"] = {
|
93
|
+
"WantedBy": "default.target",
|
94
|
+
}
|
95
|
+
|
96
|
+
try:
|
97
|
+
with open(PRIMITIVE_AGENT_SERVICE_FILEPATH, "w") as service_file:
|
98
|
+
config.write(service_file)
|
99
|
+
except IOError as exception:
|
100
|
+
print(f"populate_service_file: {exception}")
|
101
|
+
|
102
|
+
PRIMITIVE_AGENT_SERVICE_FILEPATH.chmod(0o644)
|
103
|
+
verify_service_file()
|
104
|
+
|
105
|
+
|
106
|
+
def verify_service_file():
|
107
|
+
systemctl_check = (
|
108
|
+
f"systemctl --user show {PRIMITIVE_AGENT_SERVICE} -p CanStart --value"
|
109
|
+
)
|
110
|
+
try:
|
111
|
+
output = subprocess.check_output(systemctl_check.split(" ")).decode().strip()
|
112
|
+
if output == "no":
|
113
|
+
raise Exception(f"{systemctl_check} yielded {output}")
|
114
|
+
return True
|
115
|
+
except subprocess.CalledProcessError as exception:
|
116
|
+
print("verify_service_file: ", exception)
|
117
|
+
return False
|
118
|
+
|
119
|
+
|
120
|
+
def create_stdout_file():
|
121
|
+
if not PRIMITIVE_AGENT_LOGS_FILEPATH.exists():
|
122
|
+
PRIMITIVE_AGENT_LOGS_FILEPATH.parent.mkdir(parents=True, exist_ok=True)
|
123
|
+
PRIMITIVE_AGENT_LOGS_FILEPATH.touch()
|
124
|
+
|
125
|
+
|
126
|
+
def delete_stdout_file():
|
127
|
+
if PRIMITIVE_AGENT_LOGS_FILEPATH.exists():
|
128
|
+
PRIMITIVE_AGENT_LOGS_FILEPATH.unlink()
|
129
|
+
|
130
|
+
|
131
|
+
def enable_service():
|
132
|
+
try:
|
133
|
+
enable_service = f"systemctl --user enable {PRIMITIVE_AGENT_SERVICE}"
|
134
|
+
subprocess.check_output(enable_service.split(" "))
|
135
|
+
return True
|
136
|
+
except subprocess.CalledProcessError as exception:
|
137
|
+
print("enable_service: ", exception)
|
138
|
+
return False
|
139
|
+
|
140
|
+
|
141
|
+
def start_service():
|
142
|
+
try:
|
143
|
+
start_new_service = f"systemctl --user start {PRIMITIVE_AGENT_SERVICE}"
|
144
|
+
subprocess.check_output(start_new_service.split(" "))
|
145
|
+
return True
|
146
|
+
except subprocess.CalledProcessError as exception:
|
147
|
+
print("start_service: ", exception)
|
148
|
+
return False
|
149
|
+
|
150
|
+
|
151
|
+
def view_service_logs():
|
152
|
+
follow_logs = f"tail -f -n +1 {PRIMITIVE_AGENT_LOGS_FILEPATH}"
|
153
|
+
os.system(follow_logs)
|
154
|
+
|
155
|
+
|
156
|
+
def full_service_install():
|
157
|
+
stop_service()
|
158
|
+
disable_service()
|
159
|
+
populate_service_file()
|
160
|
+
create_stdout_file()
|
161
|
+
enable_service()
|
162
|
+
start_service()
|
163
|
+
|
164
|
+
|
165
|
+
def full_service_uninstall():
|
166
|
+
stop_service()
|
167
|
+
disable_service()
|
168
|
+
if PRIMITIVE_AGENT_SERVICE_FILEPATH.exists():
|
169
|
+
PRIMITIVE_AGENT_SERVICE_FILEPATH.unlink()
|
170
|
+
delete_stdout_file()
|
@@ -0,0 +1,303 @@
|
|
1
|
+
from typing import List, Optional
|
2
|
+
from gql import gql
|
3
|
+
|
4
|
+
|
5
|
+
from primitive.utils.actions import BaseAction
|
6
|
+
|
7
|
+
|
8
|
+
class Jobs(BaseAction):
|
9
|
+
def get_jobs(
|
10
|
+
self,
|
11
|
+
organization_id: Optional[str] = None,
|
12
|
+
project_id: Optional[str] = None,
|
13
|
+
job_id: Optional[str] = None,
|
14
|
+
slug: Optional[str] = None,
|
15
|
+
first: Optional[int] = 1,
|
16
|
+
last: Optional[int] = None,
|
17
|
+
):
|
18
|
+
query = gql(
|
19
|
+
"""
|
20
|
+
fragment PageInfoFragment on PageInfo {
|
21
|
+
hasNextPage
|
22
|
+
hasPreviousPage
|
23
|
+
startCursor
|
24
|
+
endCursor
|
25
|
+
}
|
26
|
+
|
27
|
+
fragment JobFragment on Job {
|
28
|
+
id
|
29
|
+
pk
|
30
|
+
slug
|
31
|
+
name
|
32
|
+
createdAt
|
33
|
+
updatedAt
|
34
|
+
}
|
35
|
+
|
36
|
+
query jobs(
|
37
|
+
$before: String
|
38
|
+
$after: String
|
39
|
+
$first: Int
|
40
|
+
$last: Int
|
41
|
+
$filters: JobFilters
|
42
|
+
) {
|
43
|
+
jobs(
|
44
|
+
before: $before
|
45
|
+
after: $after
|
46
|
+
first: $first
|
47
|
+
last: $last
|
48
|
+
filters: $filters
|
49
|
+
) {
|
50
|
+
totalCount
|
51
|
+
pageInfo {
|
52
|
+
...PageInfoFragment
|
53
|
+
}
|
54
|
+
edges {
|
55
|
+
cursor
|
56
|
+
node {
|
57
|
+
...JobFragment
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
"""
|
63
|
+
)
|
64
|
+
|
65
|
+
filters = {}
|
66
|
+
if organization_id:
|
67
|
+
filters["organization"] = {"id": organization_id}
|
68
|
+
if project_id:
|
69
|
+
filters["project"] = {"id": project_id}
|
70
|
+
if job_id:
|
71
|
+
filters["id"] = job_id
|
72
|
+
if slug:
|
73
|
+
filters["slug"] = {"exact": slug}
|
74
|
+
|
75
|
+
variables = {
|
76
|
+
"first": first,
|
77
|
+
"last": last,
|
78
|
+
"filters": filters,
|
79
|
+
"order": {
|
80
|
+
"createdAt": "DESC",
|
81
|
+
},
|
82
|
+
}
|
83
|
+
|
84
|
+
result = self.primitive.session.execute(
|
85
|
+
query, variable_values=variables, get_execution_result=True
|
86
|
+
)
|
87
|
+
jobs = [edge["node"] for edge in result.data["jobs"]["edges"]]
|
88
|
+
return jobs
|
89
|
+
|
90
|
+
def get_job_runs(
|
91
|
+
self,
|
92
|
+
organization_id: Optional[str] = None,
|
93
|
+
project_id: Optional[str] = None,
|
94
|
+
job_id: Optional[str] = None,
|
95
|
+
reservation_id: Optional[str] = None,
|
96
|
+
git_commit_id: Optional[str] = None,
|
97
|
+
status: Optional[str] = None,
|
98
|
+
conclusion: Optional[str] = None,
|
99
|
+
first: Optional[int] = 1,
|
100
|
+
last: Optional[int] = None,
|
101
|
+
):
|
102
|
+
query = gql(
|
103
|
+
"""
|
104
|
+
fragment PageInfoFragment on PageInfo {
|
105
|
+
hasNextPage
|
106
|
+
hasPreviousPage
|
107
|
+
startCursor
|
108
|
+
endCursor
|
109
|
+
}
|
110
|
+
|
111
|
+
fragment JobRunFragment on JobRun {
|
112
|
+
id
|
113
|
+
pk
|
114
|
+
createdAt
|
115
|
+
updatedAt
|
116
|
+
completedAt
|
117
|
+
startedAt
|
118
|
+
status
|
119
|
+
conclusion
|
120
|
+
stdout
|
121
|
+
job {
|
122
|
+
id
|
123
|
+
pk
|
124
|
+
slug
|
125
|
+
name
|
126
|
+
createdAt
|
127
|
+
updatedAt
|
128
|
+
}
|
129
|
+
gitCommit {
|
130
|
+
sha
|
131
|
+
branch
|
132
|
+
repoFullName
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
query jobRuns(
|
137
|
+
$before: String
|
138
|
+
$after: String
|
139
|
+
$first: Int
|
140
|
+
$last: Int
|
141
|
+
$filters: JobRunFilters
|
142
|
+
$order: JobRunOrder
|
143
|
+
) {
|
144
|
+
jobRuns(
|
145
|
+
before: $before
|
146
|
+
after: $after
|
147
|
+
first: $first
|
148
|
+
last: $last
|
149
|
+
filters: $filters
|
150
|
+
order: $order
|
151
|
+
) {
|
152
|
+
totalCount
|
153
|
+
pageInfo {
|
154
|
+
...PageInfoFragment
|
155
|
+
}
|
156
|
+
edges {
|
157
|
+
cursor
|
158
|
+
node {
|
159
|
+
...JobRunFragment
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
"""
|
165
|
+
)
|
166
|
+
|
167
|
+
filters = {}
|
168
|
+
if organization_id:
|
169
|
+
filters["organization"] = {"id": organization_id}
|
170
|
+
if project_id:
|
171
|
+
filters["project"] = {"id": project_id}
|
172
|
+
if job_id:
|
173
|
+
filters["job"] = {"id": job_id}
|
174
|
+
if reservation_id:
|
175
|
+
filters["reservation"] = {"id": reservation_id}
|
176
|
+
if git_commit_id:
|
177
|
+
filters["gitCommit"] = {"id": git_commit_id}
|
178
|
+
if status:
|
179
|
+
filters["status"] = {"exact": status}
|
180
|
+
if conclusion:
|
181
|
+
filters["conclusion"] = {"exact": status}
|
182
|
+
|
183
|
+
variables = {
|
184
|
+
"first": first,
|
185
|
+
"last": last,
|
186
|
+
"filters": filters,
|
187
|
+
"order": {
|
188
|
+
"createdAt": "DESC",
|
189
|
+
},
|
190
|
+
}
|
191
|
+
|
192
|
+
result = self.primitive.session.execute(query, variable_values=variables)
|
193
|
+
return result
|
194
|
+
|
195
|
+
def get_job_run(self, id: str):
|
196
|
+
query = gql(
|
197
|
+
"""
|
198
|
+
fragment JobRunFragment on JobRun {
|
199
|
+
id
|
200
|
+
pk
|
201
|
+
createdAt
|
202
|
+
updatedAt
|
203
|
+
completedAt
|
204
|
+
startedAt
|
205
|
+
status
|
206
|
+
conclusion
|
207
|
+
stdout
|
208
|
+
job {
|
209
|
+
id
|
210
|
+
pk
|
211
|
+
slug
|
212
|
+
name
|
213
|
+
createdAt
|
214
|
+
updatedAt
|
215
|
+
}
|
216
|
+
gitCommit {
|
217
|
+
sha
|
218
|
+
branch
|
219
|
+
repoFullName
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
query jobRun($id: GlobalID!) {
|
224
|
+
jobRun(id: $id) {
|
225
|
+
...JobRunFragment
|
226
|
+
}
|
227
|
+
}
|
228
|
+
"""
|
229
|
+
)
|
230
|
+
variables = {"id": id}
|
231
|
+
result = self.primitive.session.execute(query, variable_values=variables)
|
232
|
+
return result
|
233
|
+
|
234
|
+
def job_run_update(
|
235
|
+
self,
|
236
|
+
id: str,
|
237
|
+
status: str = None,
|
238
|
+
conclusion: str = None,
|
239
|
+
stdout: str = None,
|
240
|
+
file_ids: Optional[List[str]] = [],
|
241
|
+
):
|
242
|
+
mutation = gql(
|
243
|
+
"""
|
244
|
+
mutation jobRunUpdate($input: JobRunUpdateInput!) {
|
245
|
+
jobRunUpdate(input: $input) {
|
246
|
+
... on JobRun {
|
247
|
+
id
|
248
|
+
status
|
249
|
+
conclusion
|
250
|
+
}
|
251
|
+
}
|
252
|
+
}
|
253
|
+
"""
|
254
|
+
)
|
255
|
+
input = {"id": id}
|
256
|
+
if status:
|
257
|
+
input["status"] = status
|
258
|
+
if conclusion:
|
259
|
+
input["conclusion"] = conclusion
|
260
|
+
if file_ids and len(file_ids) > 0:
|
261
|
+
input["files"] = file_ids
|
262
|
+
if stdout:
|
263
|
+
input["stdout"] = stdout
|
264
|
+
variables = {"input": input}
|
265
|
+
result = self.primitive.session.execute(mutation, variable_values=variables)
|
266
|
+
return result
|
267
|
+
|
268
|
+
def github_access_token_for_job_run(self, job_run_id: str):
|
269
|
+
query = gql(
|
270
|
+
"""
|
271
|
+
query ghAppTokenForJobRun($jobRunId: GlobalID!) {
|
272
|
+
ghAppTokenForJobRun(jobRunId: $jobRunId)
|
273
|
+
}
|
274
|
+
"""
|
275
|
+
)
|
276
|
+
variables = {"jobRunId": job_run_id}
|
277
|
+
result = self.primitive.session.execute(query, variable_values=variables)
|
278
|
+
return result["ghAppTokenForJobRun"]
|
279
|
+
|
280
|
+
def get_latest_job_run_for_job(
|
281
|
+
self, job_slug: Optional[str] = None, job_id: Optional[str] = None
|
282
|
+
):
|
283
|
+
if not job_slug and not job_id:
|
284
|
+
raise ValueError("job_slug or job_id is required")
|
285
|
+
jobs_results = self.get_jobs(slug=job_slug)
|
286
|
+
jobs = [edge["node"] for edge in jobs_results.data["jobs"]["edges"]]
|
287
|
+
|
288
|
+
job_id = jobs.id
|
289
|
+
job_run_results = self.get_job_runs(job_id=job_id, first=1)
|
290
|
+
job_run = [edge["node"] for edge in job_run_results.data["job_runs"]["edges"]][
|
291
|
+
0
|
292
|
+
]
|
293
|
+
return job_run
|
294
|
+
|
295
|
+
def job_run_start(
|
296
|
+
self,
|
297
|
+
job_slug: str,
|
298
|
+
job_id: str,
|
299
|
+
):
|
300
|
+
if not job_slug and not job_id:
|
301
|
+
raise ValueError("job_slug or job_id is required")
|
302
|
+
|
303
|
+
self.get_jobs(slug=job_slug)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from ..utils.printer import print_result
|
4
|
+
|
5
|
+
import typing
|
6
|
+
|
7
|
+
if typing.TYPE_CHECKING:
|
8
|
+
from ..client import Primitive
|
9
|
+
|
10
|
+
|
11
|
+
@click.group()
|
12
|
+
@click.pass_context
|
13
|
+
def cli(context):
|
14
|
+
"""Jobs Commands"""
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
@cli.command("list")
|
19
|
+
@click.pass_context
|
20
|
+
def list(
|
21
|
+
context,
|
22
|
+
organization_slug: str = None,
|
23
|
+
organization_id: str = None,
|
24
|
+
):
|
25
|
+
"""List Job"""
|
26
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
27
|
+
message = primitive.jobs.get_jobs()
|
28
|
+
print_result(message=message, context=context)
|
29
|
+
|
30
|
+
|
31
|
+
@cli.command("details")
|
32
|
+
@click.argument("job_slug")
|
33
|
+
@click.pass_context
|
34
|
+
def details(
|
35
|
+
context,
|
36
|
+
job_slug: str = None,
|
37
|
+
):
|
38
|
+
"""List Job"""
|
39
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
40
|
+
message = primitive.jobs.get_jobs(slug=job_slug)
|
41
|
+
print_result(message=message, context=context)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from gql import gql
|
3
|
+
|
4
|
+
|
5
|
+
from primitive.utils.actions import BaseAction
|
6
|
+
|
7
|
+
|
8
|
+
class Organizations(BaseAction):
|
9
|
+
def get_organizations(
|
10
|
+
self,
|
11
|
+
organization_id: Optional[str] = None,
|
12
|
+
slug: Optional[str] = None,
|
13
|
+
first: Optional[int] = 1,
|
14
|
+
last: Optional[int] = None,
|
15
|
+
):
|
16
|
+
query = gql(
|
17
|
+
"""
|
18
|
+
fragment PageInfoFragment on PageInfo {
|
19
|
+
hasNextPage
|
20
|
+
hasPreviousPage
|
21
|
+
startCursor
|
22
|
+
endCursor
|
23
|
+
}
|
24
|
+
|
25
|
+
fragment OrganizationFragment on Organization {
|
26
|
+
id
|
27
|
+
pk
|
28
|
+
slug
|
29
|
+
name
|
30
|
+
createdAt
|
31
|
+
updatedAt
|
32
|
+
}
|
33
|
+
|
34
|
+
query organizations(
|
35
|
+
$before: String
|
36
|
+
$after: String
|
37
|
+
$first: Int
|
38
|
+
$last: Int
|
39
|
+
$filters: OrganizationFilters
|
40
|
+
$order: OrganizationOrder
|
41
|
+
) {
|
42
|
+
organizations(
|
43
|
+
before: $before
|
44
|
+
after: $after
|
45
|
+
first: $first
|
46
|
+
last: $last
|
47
|
+
filters: $filters
|
48
|
+
order: $order
|
49
|
+
) {
|
50
|
+
totalCount
|
51
|
+
pageInfo {
|
52
|
+
...PageInfoFragment
|
53
|
+
}
|
54
|
+
edges {
|
55
|
+
cursor
|
56
|
+
node {
|
57
|
+
...OrganizationFragment
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
"""
|
63
|
+
)
|
64
|
+
|
65
|
+
filters = {}
|
66
|
+
if organization_id:
|
67
|
+
filters["organization"] = {"id": organization_id}
|
68
|
+
if slug:
|
69
|
+
filters["slug"] = {"exact": slug}
|
70
|
+
|
71
|
+
variables = {
|
72
|
+
"first": first,
|
73
|
+
"last": last,
|
74
|
+
"filters": filters,
|
75
|
+
"order": {
|
76
|
+
"createdAt": "DESC",
|
77
|
+
},
|
78
|
+
}
|
79
|
+
|
80
|
+
result = self.primitive.session.execute(
|
81
|
+
query, variable_values=variables, get_execution_result=True
|
82
|
+
)
|
83
|
+
organizations = [edge["node"] for edge in result.data["organizations"]["edges"]]
|
84
|
+
return organizations
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from ..utils.printer import print_result
|
4
|
+
|
5
|
+
import typing
|
6
|
+
|
7
|
+
if typing.TYPE_CHECKING:
|
8
|
+
from ..client import Primitive
|
9
|
+
|
10
|
+
|
11
|
+
@click.group()
|
12
|
+
@click.pass_context
|
13
|
+
def cli(context):
|
14
|
+
"""Organizations Commands"""
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
@cli.command("list")
|
19
|
+
@click.pass_context
|
20
|
+
def details(context):
|
21
|
+
"""List Organizations"""
|
22
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
23
|
+
message = primitive.organizations.get_organizations()
|
24
|
+
print_result(message=message, context=context)
|
primitive/projects/actions.py
CHANGED
@@ -1,175 +1,79 @@
|
|
1
|
-
from typing import List, Optional
|
2
1
|
from gql import gql
|
3
2
|
|
4
|
-
|
3
|
+
from typing import Optional
|
5
4
|
from primitive.utils.actions import BaseAction
|
6
5
|
|
7
6
|
|
8
7
|
class Projects(BaseAction):
|
9
|
-
|
8
|
+
|
9
|
+
def get_projects(
|
10
10
|
self,
|
11
11
|
organization_id: Optional[str] = None,
|
12
|
-
|
13
|
-
job_id: Optional[str] = None,
|
14
|
-
reservation_id: Optional[str] = None,
|
15
|
-
git_commit_id: Optional[str] = None,
|
16
|
-
status: Optional[str] = None,
|
17
|
-
conclusion: Optional[str] = None,
|
12
|
+
slug: Optional[str] = None,
|
18
13
|
first: Optional[int] = 1,
|
19
14
|
last: Optional[int] = None,
|
20
15
|
):
|
21
16
|
query = gql(
|
22
|
-
"""
|
23
|
-
fragment PageInfoFragment on PageInfo {
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
}
|
17
|
+
"""
|
18
|
+
fragment PageInfoFragment on PageInfo {
|
19
|
+
hasNextPage
|
20
|
+
hasPreviousPage
|
21
|
+
startCursor
|
22
|
+
endCursor
|
23
|
+
}
|
29
24
|
|
30
|
-
fragment
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
conclusion
|
39
|
-
stdout
|
40
|
-
job {
|
41
|
-
id
|
42
|
-
pk
|
43
|
-
slug
|
44
|
-
name
|
45
|
-
createdAt
|
46
|
-
updatedAt
|
47
|
-
}
|
48
|
-
gitCommit {
|
49
|
-
sha
|
50
|
-
branch
|
51
|
-
repoFullName
|
52
|
-
}
|
53
|
-
}
|
25
|
+
fragment ProjectFragment on Project {
|
26
|
+
id
|
27
|
+
pk
|
28
|
+
slug
|
29
|
+
name
|
30
|
+
createdAt
|
31
|
+
updatedAt
|
32
|
+
}
|
54
33
|
|
55
|
-
query
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
}
|
83
|
-
"""
|
34
|
+
query projects(
|
35
|
+
$before: String
|
36
|
+
$after: String
|
37
|
+
$first: Int
|
38
|
+
$last: Int
|
39
|
+
$filters: ProjectFilters
|
40
|
+
) {
|
41
|
+
projects(
|
42
|
+
before: $before
|
43
|
+
after: $after
|
44
|
+
first: $first
|
45
|
+
last: $last
|
46
|
+
filters: $filters
|
47
|
+
) {
|
48
|
+
totalCount
|
49
|
+
pageInfo {
|
50
|
+
...PageInfoFragment
|
51
|
+
}
|
52
|
+
edges {
|
53
|
+
cursor
|
54
|
+
node {
|
55
|
+
...ProjectFragment
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
"""
|
84
61
|
)
|
85
62
|
|
86
63
|
filters = {}
|
87
64
|
if organization_id:
|
88
65
|
filters["organization"] = {"id": organization_id}
|
89
|
-
if
|
90
|
-
filters["
|
91
|
-
if job_id:
|
92
|
-
filters["job"] = {"id": job_id}
|
93
|
-
if reservation_id:
|
94
|
-
filters["reservation"] = {"id": reservation_id}
|
95
|
-
if git_commit_id:
|
96
|
-
filters["gitCommit"] = {"id": git_commit_id}
|
97
|
-
if status:
|
98
|
-
filters["status"] = {"exact": status}
|
99
|
-
if conclusion:
|
100
|
-
filters["conclusion"] = {"exact": status}
|
66
|
+
if slug:
|
67
|
+
filters["slug"] = {"exact": slug}
|
101
68
|
|
102
69
|
variables = {
|
103
70
|
"first": first,
|
104
71
|
"last": last,
|
105
72
|
"filters": filters,
|
106
|
-
"order": {
|
107
|
-
"createdAt": "DESC",
|
108
|
-
},
|
109
73
|
}
|
110
74
|
|
111
|
-
result = self.primitive.session.execute(
|
112
|
-
|
113
|
-
|
114
|
-
def get_job_run(self, id: str):
|
115
|
-
query = gql(
|
116
|
-
"""
|
117
|
-
query jobRun($id: GlobalID!) {
|
118
|
-
jobRun(id: $id) {
|
119
|
-
id
|
120
|
-
organization {
|
121
|
-
id
|
122
|
-
}
|
123
|
-
}
|
124
|
-
}
|
125
|
-
"""
|
126
|
-
)
|
127
|
-
variables = {"id": id}
|
128
|
-
result = self.primitive.session.execute(query, variable_values=variables)
|
129
|
-
return result
|
130
|
-
|
131
|
-
def job_run_update(
|
132
|
-
self,
|
133
|
-
id: str,
|
134
|
-
status: str = None,
|
135
|
-
conclusion: str = None,
|
136
|
-
stdout: str = None,
|
137
|
-
file_ids: Optional[List[str]] = [],
|
138
|
-
):
|
139
|
-
mutation = gql(
|
140
|
-
"""
|
141
|
-
mutation jobRunUpdate($input: JobRunUpdateInput!) {
|
142
|
-
jobRunUpdate(input: $input) {
|
143
|
-
... on JobRun {
|
144
|
-
id
|
145
|
-
status
|
146
|
-
conclusion
|
147
|
-
}
|
148
|
-
}
|
149
|
-
}
|
150
|
-
"""
|
151
|
-
)
|
152
|
-
input = {"id": id}
|
153
|
-
if status:
|
154
|
-
input["status"] = status
|
155
|
-
if conclusion:
|
156
|
-
input["conclusion"] = conclusion
|
157
|
-
if file_ids and len(file_ids) > 0:
|
158
|
-
input["files"] = file_ids
|
159
|
-
if stdout:
|
160
|
-
input["stdout"] = stdout
|
161
|
-
variables = {"input": input}
|
162
|
-
result = self.primitive.session.execute(mutation, variable_values=variables)
|
163
|
-
return result
|
164
|
-
|
165
|
-
def github_access_token_for_job_run(self, job_run_id: str):
|
166
|
-
query = gql(
|
167
|
-
"""
|
168
|
-
query ghAppTokenForJobRun($jobRunId: GlobalID!) {
|
169
|
-
ghAppTokenForJobRun(jobRunId: $jobRunId)
|
170
|
-
}
|
171
|
-
"""
|
75
|
+
result = self.primitive.session.execute(
|
76
|
+
query, variable_values=variables, get_execution_result=True
|
172
77
|
)
|
173
|
-
|
174
|
-
|
175
|
-
return result["ghAppTokenForJobRun"]
|
78
|
+
projects = [edge["node"] for edge in result.data["projects"]["edges"]]
|
79
|
+
return projects
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from ..utils.printer import print_result
|
4
|
+
|
5
|
+
import typing
|
6
|
+
|
7
|
+
if typing.TYPE_CHECKING:
|
8
|
+
from ..client import Primitive
|
9
|
+
|
10
|
+
|
11
|
+
@click.group()
|
12
|
+
@click.pass_context
|
13
|
+
def cli(context):
|
14
|
+
"""Projects Commands"""
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
@cli.command("list")
|
19
|
+
@click.pass_context
|
20
|
+
def list(context):
|
21
|
+
"""List Projects"""
|
22
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
23
|
+
message = primitive.projects.get_projects()
|
24
|
+
print_result(message=message, context=context)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: primitive
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.14
|
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,12 +1,16 @@
|
|
1
|
-
primitive/__about__.py,sha256=
|
1
|
+
primitive/__about__.py,sha256=NZWfnlUO354pWRTdV9CUZL2iipJ1paYR9Gljq6eTciM,129
|
2
2
|
primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
|
3
|
-
primitive/cli.py,sha256=
|
4
|
-
primitive/client.py,sha256=
|
5
|
-
primitive/agent/actions.py,sha256=
|
3
|
+
primitive/cli.py,sha256=VA1c9RiH79mqYvIvYT0msu4tEPlYiU1C2LstbdzyjWk,2291
|
4
|
+
primitive/client.py,sha256=FYc-Onu1c0fjttSWlhK0B1ZOizDsP3qGtOAUHvPGqG0,2410
|
5
|
+
primitive/agent/actions.py,sha256=8G9-QjUKRvlvlZ_6NyZr2KvvW1FTS54q-KPUzyAPccE,3657
|
6
6
|
primitive/agent/commands.py,sha256=-dVDilELfkGfbZB7qfEPs77Dm1oT62qJj4tsIk4KoxI,254
|
7
7
|
primitive/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
primitive/auth/actions.py,sha256=N2bGcwXNsB89pzs66gF9A5_WzUScY5fhfOyWixqo2y8,1054
|
9
9
|
primitive/auth/commands.py,sha256=JahUq0E2e7Xa-FX1WEUv7TgM6ieDvNH4VwRRtxAW7HE,2340
|
10
|
+
primitive/daemons/actions.py,sha256=Nt3yNtbBhen0jK4sRsH_N7AP3UBuyL48VaUhtC7wYq8,2015
|
11
|
+
primitive/daemons/commands.py,sha256=-Muh-6ib4uAVtPn_67AcMrDwuCwYlCnRQozCi2Xurmk,1726
|
12
|
+
primitive/daemons/launch_agents.py,sha256=xR_JDL93mt5-fSbj-v3qvYFvLqfn486fPNbNxZOb1wU,4412
|
13
|
+
primitive/daemons/launch_service.py,sha256=3ktr0n0rSNA-IV6hQ8hbG50L2Y3V8-IeW79C8CrZi8U,5203
|
10
14
|
primitive/files/actions.py,sha256=f4JN3QFB2WXw-0JpnE-4-movnqtvXIpCrGd_9pdkeW4,2624
|
11
15
|
primitive/files/commands.py,sha256=DDizo3xJnU3KLUBTMeeM72viVpnJinLwxs84tmqKhqo,810
|
12
16
|
primitive/git/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -16,10 +20,15 @@ primitive/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
16
20
|
primitive/graphql/sdk.py,sha256=BhCGmDtc4sNnH8CxbQSJyFwOZ-ZSqMtjsxMB3JRBhPw,1456
|
17
21
|
primitive/hardware/actions.py,sha256=Ea3_2E3F_3WapV60g_mOIcpXhadoknwihR7slXyUWtk,18840
|
18
22
|
primitive/hardware/commands.py,sha256=QE7LLeFdfOqlvz3JwdwJJRZAY3fHI1zB9kYmmDajpq0,1477
|
23
|
+
primitive/jobs/actions.py,sha256=ftVWIB10PxTrFsDmSd9C3WV3puiQftTLBKFIjcS_StI,7562
|
24
|
+
primitive/jobs/commands.py,sha256=MxPCkBEYW_eLNqgCRYeyj7ZcLOFAWfpVZlqDR2Y_S0o,830
|
19
25
|
primitive/lint/actions.py,sha256=PDw0fkIkI5hHHjoHaAiXvQUocwHZkgB2mfI-LGMl6TI,2267
|
20
26
|
primitive/lint/commands.py,sha256=3CZvkOEMpJspJWmaQzA5bpPKx0_VCijQIXA9l-eTnZE,487
|
27
|
+
primitive/organizations/actions.py,sha256=e0V4E1UK1IcBJsWWH6alHYUmArhzPrBqZ8WkHPIcLq0,2268
|
28
|
+
primitive/organizations/commands.py,sha256=_dwgVEJCqMa5VgB_7P1wLPFc0AuT1p9dtyR9JRr4kpw,487
|
21
29
|
primitive/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
primitive/projects/actions.py,sha256=
|
30
|
+
primitive/projects/actions.py,sha256=L2M2SvFdDr2XnpoxFl61jXmIriD4T1vVMoBFgCy6SY4,2062
|
31
|
+
primitive/projects/commands.py,sha256=Fqqgpi4cm6zOgkHK--0F0hiiIj32BmgZ-h1MydmWwdE,464
|
23
32
|
primitive/simulations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
33
|
primitive/simulations/actions.py,sha256=YR0oxxd7_kuUIH77BWZLUs9rLRiSJztPPhpgDJU2PbY,1267
|
25
34
|
primitive/utils/actions.py,sha256=HOFrmM3-0A_A3NS84MqrZ6JmQEiiPSoDqEeuu6b_qfQ,196
|
@@ -30,8 +39,8 @@ primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIU
|
|
30
39
|
primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
|
31
40
|
primitive/utils/shell.py,sha256=-7UjQaBqSGHzEEyX8pNjeYFFP0P3lVnDV0OkgPz1qHU,1050
|
32
41
|
primitive/utils/verible.py,sha256=QYczN1IvxODfj4jeq0nqjFuF0Oi0Zdx-Q32ySOJgcw8,2205
|
33
|
-
primitive-0.1.
|
34
|
-
primitive-0.1.
|
35
|
-
primitive-0.1.
|
36
|
-
primitive-0.1.
|
37
|
-
primitive-0.1.
|
42
|
+
primitive-0.1.14.dist-info/METADATA,sha256=L7Npr3zJ77e2VpLmfKrhJ7bb3OuI2LKLxIS7Nvak7SQ,1818
|
43
|
+
primitive-0.1.14.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
44
|
+
primitive-0.1.14.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
|
45
|
+
primitive-0.1.14.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
|
46
|
+
primitive-0.1.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|