primitive 0.1.58__py3-none-any.whl → 0.1.59__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.
Files changed (63) hide show
  1. primitive/__about__.py +1 -1
  2. primitive/agent/__init__.py +0 -0
  3. primitive/agent/actions.py +7 -4
  4. primitive/agent/runner.py +8 -6
  5. primitive/auth/actions.py +5 -12
  6. primitive/auth/graphql/__init__.py +0 -0
  7. primitive/auth/graphql/queries.py +13 -0
  8. primitive/cli.py +11 -5
  9. primitive/client.py +4 -0
  10. primitive/daemons/__init__.py +0 -0
  11. primitive/exec/__init__.py +0 -0
  12. primitive/exec/actions.py +50 -0
  13. primitive/exec/commands.py +22 -0
  14. primitive/files/__init__.py +0 -0
  15. primitive/files/actions.py +9 -16
  16. primitive/files/graphql/__init__.py +0 -0
  17. primitive/files/graphql/mutations.py +11 -0
  18. primitive/git/actions.py +11 -11
  19. primitive/git/commands.py +7 -6
  20. primitive/git/graphql/__init__.py +0 -0
  21. primitive/git/graphql/queries.py +7 -0
  22. primitive/graphql/relay.py +32 -0
  23. primitive/graphql/utility_fragments.py +19 -0
  24. primitive/hardware/__init__.py +0 -0
  25. primitive/hardware/actions.py +74 -121
  26. primitive/hardware/commands.py +15 -5
  27. primitive/hardware/graphql/__init__.py +0 -0
  28. primitive/hardware/graphql/fragments.py +22 -0
  29. primitive/hardware/graphql/mutations.py +45 -0
  30. primitive/hardware/graphql/queries.py +31 -0
  31. primitive/jobs/__init__.py +0 -0
  32. primitive/jobs/actions.py +32 -201
  33. primitive/jobs/graphql/__init__.py +0 -0
  34. primitive/jobs/graphql/fragments.py +47 -0
  35. primitive/jobs/graphql/mutations.py +11 -0
  36. primitive/jobs/graphql/queries.py +100 -0
  37. primitive/lint/__init__.py +0 -0
  38. primitive/organizations/__init__.py +0 -0
  39. primitive/organizations/actions.py +4 -49
  40. primitive/organizations/graphql/__init__.py +0 -0
  41. primitive/organizations/graphql/fragments.py +10 -0
  42. primitive/organizations/graphql/mutations.py +0 -0
  43. primitive/organizations/graphql/queries.py +38 -0
  44. primitive/projects/actions.py +5 -47
  45. primitive/projects/graphql/__init__.py +0 -0
  46. primitive/projects/graphql/fragments.py +10 -0
  47. primitive/projects/graphql/mutations.py +0 -0
  48. primitive/projects/graphql/queries.py +36 -0
  49. primitive/reservations/__init__.py +0 -0
  50. primitive/reservations/actions.py +134 -0
  51. primitive/reservations/commands.py +67 -0
  52. primitive/reservations/graphql/__init__.py +0 -0
  53. primitive/reservations/graphql/fragments.py +40 -0
  54. primitive/reservations/graphql/mutations.py +29 -0
  55. primitive/reservations/graphql/queries.py +47 -0
  56. primitive/sim/actions.py +12 -9
  57. primitive/utils/__init__.py +0 -0
  58. {primitive-0.1.58.dist-info → primitive-0.1.59.dist-info}/METADATA +1 -1
  59. primitive-0.1.59.dist-info/RECORD +95 -0
  60. primitive-0.1.58.dist-info/RECORD +0 -53
  61. {primitive-0.1.58.dist-info → primitive-0.1.59.dist-info}/WHEEL +0 -0
  62. {primitive-0.1.58.dist-info → primitive-0.1.59.dist-info}/entry_points.txt +0 -0
  63. {primitive-0.1.58.dist-info → primitive-0.1.59.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,47 @@
1
+ job_fragment = """
2
+ fragment JobFragment on Job {
3
+ id
4
+ pk
5
+ slug
6
+ name
7
+ createdAt
8
+ updatedAt
9
+ }
10
+ """
11
+
12
+ job_run_fragment = """
13
+ fragment JobRunFragment on JobRun {
14
+ id
15
+ pk
16
+ createdAt
17
+ updatedAt
18
+ completedAt
19
+ startedAt
20
+ status
21
+ conclusion
22
+ job {
23
+ id
24
+ pk
25
+ slug
26
+ name
27
+ createdAt
28
+ updatedAt
29
+ }
30
+ jobSettings {
31
+ containerArgs
32
+ rootDirectory
33
+ }
34
+ gitCommit {
35
+ sha
36
+ branch
37
+ repoFullName
38
+ }
39
+ }
40
+ """
41
+
42
+ job_run_status_fragment = """
43
+ fragment JobRunStatusFragment on JobRun {
44
+ id
45
+ status
46
+ }
47
+ """
@@ -0,0 +1,11 @@
1
+ job_run_update_mutation = """
2
+ mutation jobRunUpdate($input: JobRunUpdateInput!) {
3
+ jobRunUpdate(input: $input) {
4
+ ... on JobRun {
5
+ id
6
+ status
7
+ conclusion
8
+ }
9
+ }
10
+ }
11
+ """
@@ -0,0 +1,100 @@
1
+ from primitive.graphql.utility_fragments import page_info_fragment
2
+
3
+ from .fragments import job_fragment, job_run_fragment, job_run_status_fragment
4
+
5
+ jobs_query = (
6
+ page_info_fragment
7
+ + job_fragment
8
+ + """
9
+ query jobs(
10
+ $before: String
11
+ $after: String
12
+ $first: Int
13
+ $last: Int
14
+ $filters: JobFilters
15
+ ) {
16
+ jobs(
17
+ before: $before
18
+ after: $after
19
+ first: $first
20
+ last: $last
21
+ filters: $filters
22
+ ) {
23
+ totalCount
24
+ pageInfo {
25
+ ...PageInfoFragment
26
+ }
27
+ edges {
28
+ cursor
29
+ node {
30
+ ...JobFragment
31
+ }
32
+ }
33
+ }
34
+ }
35
+ """
36
+ )
37
+
38
+
39
+ job_runs_query = (
40
+ page_info_fragment
41
+ + job_run_fragment
42
+ + """
43
+ query jobRuns(
44
+ $before: String
45
+ $after: String
46
+ $first: Int
47
+ $last: Int
48
+ $filters: JobRunFilters
49
+ $order: JobRunOrder
50
+ ) {
51
+ jobRuns(
52
+ before: $before
53
+ after: $after
54
+ first: $first
55
+ last: $last
56
+ filters: $filters
57
+ order: $order
58
+ ) {
59
+ totalCount
60
+ pageInfo {
61
+ ...PageInfoFragment
62
+ }
63
+ edges {
64
+ cursor
65
+ node {
66
+ ...JobRunFragment
67
+ }
68
+ }
69
+ }
70
+ }
71
+ """
72
+ )
73
+
74
+ job_run_query = (
75
+ job_run_fragment
76
+ + """
77
+ query jobRun($id: GlobalID!) {
78
+ jobRun(id: $id) {
79
+ ...JobRunFragment
80
+ }
81
+ }
82
+ """
83
+ )
84
+
85
+ github_app_token_for_job_run_query = """
86
+ query ghAppTokenForJobRun($jobRunId: GlobalID!) {
87
+ ghAppTokenForJobRun(jobRunId: $jobRunId)
88
+ }
89
+ """
90
+
91
+ job_run_status_query = (
92
+ job_run_status_fragment
93
+ + """
94
+ query jobRun($id: GlobalID!) {
95
+ jobRun(id: $id) {
96
+ ...JobRunStatusFragment
97
+ }
98
+ }
99
+ """
100
+ )
File without changes
File without changes
@@ -1,9 +1,11 @@
1
1
  from typing import Optional
2
- from gql import gql
3
2
 
3
+ from gql import gql
4
4
 
5
5
  from primitive.utils.actions import BaseAction
6
+
6
7
  from ..utils.auth import guard
8
+ from .graphql.queries import organizations_query
7
9
 
8
10
 
9
11
  class Organizations(BaseAction):
@@ -15,54 +17,7 @@ class Organizations(BaseAction):
15
17
  first: Optional[int] = 1,
16
18
  last: Optional[int] = None,
17
19
  ):
18
- query = gql(
19
- """
20
- fragment PageInfoFragment on PageInfo {
21
- hasNextPage
22
- hasPreviousPage
23
- startCursor
24
- endCursor
25
- }
26
-
27
- fragment OrganizationFragment on Organization {
28
- id
29
- pk
30
- slug
31
- name
32
- createdAt
33
- updatedAt
34
- }
35
-
36
- query organizations(
37
- $before: String
38
- $after: String
39
- $first: Int
40
- $last: Int
41
- $filters: OrganizationFilters
42
- $order: OrganizationOrder
43
- ) {
44
- organizations(
45
- before: $before
46
- after: $after
47
- first: $first
48
- last: $last
49
- filters: $filters
50
- order: $order
51
- ) {
52
- totalCount
53
- pageInfo {
54
- ...PageInfoFragment
55
- }
56
- edges {
57
- cursor
58
- node {
59
- ...OrganizationFragment
60
- }
61
- }
62
- }
63
- }
64
- """
65
- )
20
+ query = gql(organizations_query)
66
21
 
67
22
  filters = {}
68
23
  if organization_id:
File without changes
@@ -0,0 +1,10 @@
1
+ organization_fragment = """
2
+ fragment OrganizationFragment on Organization {
3
+ id
4
+ pk
5
+ slug
6
+ name
7
+ createdAt
8
+ updatedAt
9
+ }
10
+ """
File without changes
@@ -0,0 +1,38 @@
1
+ from primitive.graphql.utility_fragments import page_info_fragment
2
+
3
+ from .fragments import organization_fragment
4
+
5
+ organizations_query = (
6
+ page_info_fragment
7
+ + organization_fragment
8
+ + """
9
+ query organizations(
10
+ $before: String
11
+ $after: String
12
+ $first: Int
13
+ $last: Int
14
+ $filters: OrganizationFilters
15
+ $order: OrganizationOrder
16
+ ) {
17
+ organizations(
18
+ before: $before
19
+ after: $after
20
+ first: $first
21
+ last: $last
22
+ filters: $filters
23
+ order: $order
24
+ ) {
25
+ totalCount
26
+ pageInfo {
27
+ ...PageInfoFragment
28
+ }
29
+ edges {
30
+ cursor
31
+ node {
32
+ ...OrganizationFragment
33
+ }
34
+ }
35
+ }
36
+ }
37
+ """
38
+ )
@@ -1,8 +1,11 @@
1
+ from typing import Optional
2
+
1
3
  from gql import gql
2
4
 
3
- from typing import Optional
4
5
  from primitive.utils.actions import BaseAction
6
+
5
7
  from ..utils.auth import guard
8
+ from .graphql.queries import projects_query
6
9
 
7
10
 
8
11
  class Projects(BaseAction):
@@ -14,52 +17,7 @@ class Projects(BaseAction):
14
17
  first: Optional[int] = 1,
15
18
  last: Optional[int] = None,
16
19
  ):
17
- query = gql(
18
- """
19
- fragment PageInfoFragment on PageInfo {
20
- hasNextPage
21
- hasPreviousPage
22
- startCursor
23
- endCursor
24
- }
25
-
26
- fragment ProjectFragment on Project {
27
- id
28
- pk
29
- slug
30
- name
31
- createdAt
32
- updatedAt
33
- }
34
-
35
- query projects(
36
- $before: String
37
- $after: String
38
- $first: Int
39
- $last: Int
40
- $filters: ProjectFilters
41
- ) {
42
- projects(
43
- before: $before
44
- after: $after
45
- first: $first
46
- last: $last
47
- filters: $filters
48
- ) {
49
- totalCount
50
- pageInfo {
51
- ...PageInfoFragment
52
- }
53
- edges {
54
- cursor
55
- node {
56
- ...ProjectFragment
57
- }
58
- }
59
- }
60
- }
61
- """
62
- )
20
+ query = gql(projects_query)
63
21
 
64
22
  filters = {}
65
23
  if organization_id:
File without changes
@@ -0,0 +1,10 @@
1
+ project_fragment = """
2
+ fragment ProjectFragment on Project {
3
+ id
4
+ pk
5
+ slug
6
+ name
7
+ createdAt
8
+ updatedAt
9
+ }
10
+ """
File without changes
@@ -0,0 +1,36 @@
1
+ from primitive.graphql.utility_fragments import page_info_fragment
2
+
3
+ from .fragments import project_fragment
4
+
5
+ projects_query = (
6
+ page_info_fragment
7
+ + project_fragment
8
+ + """
9
+ query projects(
10
+ $before: String
11
+ $after: String
12
+ $first: Int
13
+ $last: Int
14
+ $filters: ProjectFilters
15
+ ) {
16
+ projects(
17
+ before: $before
18
+ after: $after
19
+ first: $first
20
+ last: $last
21
+ filters: $filters
22
+ ) {
23
+ totalCount
24
+ pageInfo {
25
+ ...PageInfoFragment
26
+ }
27
+ edges {
28
+ cursor
29
+ node {
30
+ ...ProjectFragment
31
+ }
32
+ }
33
+ }
34
+ }
35
+ """
36
+ )
File without changes
@@ -0,0 +1,134 @@
1
+ import typing
2
+ from time import sleep
3
+
4
+ from primitive.graphql.relay import from_base64
5
+
6
+ if typing.TYPE_CHECKING:
7
+ pass
8
+
9
+ from typing import List, Optional
10
+
11
+ from gql import gql
12
+
13
+ from primitive.utils.actions import BaseAction
14
+
15
+ from ..utils.auth import guard
16
+ from .graphql.mutations import reservation_create_mutation, reservation_release_mutation
17
+ from .graphql.queries import reservation_query, reservations_query
18
+
19
+
20
+ class Reservations(BaseAction):
21
+ def __init__(self, *args, **kwargs) -> None:
22
+ super().__init__(*args, **kwargs)
23
+
24
+ @guard
25
+ def get_reservations(
26
+ self,
27
+ status: str = "in_progress",
28
+ ):
29
+ query = gql(reservations_query)
30
+
31
+ filters = {}
32
+ if status:
33
+ filters["status"] = {"exact": status}
34
+
35
+ variables = {
36
+ "filters": filters,
37
+ }
38
+ result = self.primitive.session.execute(
39
+ query, variable_values=variables, get_execution_result=True
40
+ )
41
+ return result
42
+
43
+ @guard
44
+ def get_reservation(self, reservation_id: str):
45
+ query = gql(reservation_query)
46
+
47
+ variables = {
48
+ "id": reservation_id,
49
+ }
50
+
51
+ result = self.primitive.session.execute(
52
+ query, variable_values=variables, get_execution_result=True
53
+ )
54
+ return result
55
+
56
+ @guard
57
+ def create_reservation(
58
+ self,
59
+ reason: str,
60
+ requested_hardware_ids: Optional[List[str]] = None,
61
+ organization_id: Optional[str] = None,
62
+ hardware_identifier: Optional[str] = None,
63
+ ):
64
+ mutation = gql(reservation_create_mutation)
65
+
66
+ if hardware_identifier and not requested_hardware_ids:
67
+ hardware = self.primitive.hardware.get_hardware_from_slug_or_id(
68
+ hardware_identifier=hardware_identifier
69
+ )
70
+ requested_hardware_ids = [hardware["id"]]
71
+
72
+ if not organization_id:
73
+ whoami_result = self.primitive.auth.whoami()
74
+ default_organization = whoami_result.data["whoami"]["defaultOrganization"]
75
+ organization_id = default_organization["id"]
76
+
77
+ input = {
78
+ "requestedHardwareIds": requested_hardware_ids,
79
+ "reason": reason,
80
+ "organizationId": organization_id,
81
+ }
82
+
83
+ variables = {"input": input}
84
+ result = self.primitive.session.execute(
85
+ mutation, variable_values=variables, get_execution_result=True
86
+ )
87
+ return result
88
+
89
+ @guard
90
+ def release_reservation(self, reservation_or_hardware_identifier: str):
91
+ mutation = gql(reservation_release_mutation)
92
+ try:
93
+ # check if it is a base64 encoded id
94
+ type_name, _id = from_base64(reservation_or_hardware_identifier)
95
+ if type_name == "Reservation":
96
+ reservation_id = reservation_or_hardware_identifier
97
+ elif type_name == "Hardware":
98
+ hardware = self.primitive.hardware.get_hardware_from_slug_or_id(
99
+ hardware_identifier=reservation_or_hardware_identifier
100
+ )
101
+ reservation_id = hardware["activeReservation"]["id"]
102
+ except ValueError:
103
+ # if not, its a string and check for it here
104
+ hardware = self.primitive.hardware.get_hardware_from_slug_or_id(
105
+ hardware_identifier=reservation_or_hardware_identifier
106
+ )
107
+ reservation_id = hardware["activeReservation"]["id"]
108
+
109
+ input = {
110
+ "reservationId": reservation_id,
111
+ }
112
+ variables = {"input": input}
113
+ result = self.primitive.session.execute(
114
+ mutation, variable_values=variables, get_execution_result=True
115
+ )
116
+ return result
117
+
118
+ @guard
119
+ def wait_for_reservation_status(self, reservation_id: str, desired_status: str):
120
+ reservation_result = self.get_reservation(reservation_id=reservation_id)
121
+ reservation = reservation_result.data["reservation"]
122
+ current_status = reservation["status"]
123
+
124
+ sleep_amount = 1
125
+ while current_status != desired_status:
126
+ reservation_result = self.get_reservation(reservation_id=reservation_id)
127
+ reservation = reservation_result.data["reservation"]
128
+ current_status = reservation["status"]
129
+ if current_status == desired_status:
130
+ break
131
+ sleep(sleep_amount)
132
+ sleep_amount += 1
133
+
134
+ return reservation
@@ -0,0 +1,67 @@
1
+ import typing
2
+
3
+ import click
4
+
5
+ if typing.TYPE_CHECKING:
6
+ from ..client import Primitive
7
+ from typing import Optional
8
+
9
+ from ..utils.printer import print_result
10
+
11
+
12
+ @click.group()
13
+ @click.pass_context
14
+ def cli(context):
15
+ """Reservations"""
16
+ pass
17
+
18
+
19
+ @cli.command("list")
20
+ @click.pass_context
21
+ @click.option("--status", default="in_progress", type=str, help="Filter by status")
22
+ def list(context, status: Optional[str] = "in_progress"):
23
+ """List reservations"""
24
+ primitive: Primitive = context.obj.get("PRIMITIVE")
25
+ get_reservations_result = primitive.reservations.get_reservations(status=status)
26
+ message = get_reservations_result.data
27
+ print_result(message=message, context=context)
28
+
29
+
30
+ @cli.command("get")
31
+ @click.pass_context
32
+ @click.argument("reservation_id", type=str)
33
+ def get(context, reservation_id: str):
34
+ """Get a reservation"""
35
+ primitive: Primitive = context.obj.get("PRIMITIVE")
36
+ get_reservation_result = primitive.reservations.get_reservation(
37
+ reservation_id=reservation_id
38
+ )
39
+ message = get_reservation_result.data
40
+ print_result(message=message, context=context)
41
+
42
+
43
+ @cli.command("create")
44
+ @click.pass_context
45
+ @click.argument("hardware_identifier", type=str)
46
+ @click.argument("reason", type=str)
47
+ def create_reservation(context, hardware_identifier: str, reason: str):
48
+ """Crate a reservation by a Hardware's ID or Slug"""
49
+ primitive: Primitive = context.obj.get("PRIMITIVE")
50
+ create_reservation_result = primitive.reservations.create_reservation(
51
+ hardware_identifier=hardware_identifier, reason=reason
52
+ )
53
+ message = create_reservation_result.data
54
+ print_result(message=message, context=context)
55
+
56
+
57
+ @cli.command("release")
58
+ @click.pass_context
59
+ @click.argument("reservation_or_hardware_identifier", type=str)
60
+ def release_reservation(context, reservation_or_hardware_identifier: str):
61
+ """Release a reservation by Reservation ID, Hardware ID or Hardware Slug"""
62
+ primitive: Primitive = context.obj.get("PRIMITIVE")
63
+ release_reservation_result = primitive.reservations.release_reservation(
64
+ reservation_or_hardware_identifier=reservation_or_hardware_identifier
65
+ )
66
+ message = release_reservation_result.data
67
+ print_result(message=message, context=context)
File without changes
@@ -0,0 +1,40 @@
1
+ reservation_fragment = """
2
+ fragment ReservationFragment on Reservation {
3
+ id
4
+ pk
5
+ createdAt
6
+ updatedAt
7
+ createdBy {
8
+ id
9
+ pk
10
+ email
11
+ username
12
+ displayName
13
+ }
14
+ hardware {
15
+ id
16
+ pk
17
+ name
18
+ slug
19
+ createdAt
20
+ updatedAt
21
+ isAvailable
22
+ isOnline
23
+ isQuarantined
24
+ isHealthy
25
+ capabilities {
26
+ id
27
+ pk
28
+ slug
29
+ name
30
+ }
31
+ }
32
+ reason
33
+ startedAt
34
+ endedAt
35
+ elapsedTime
36
+ status
37
+ conclusion
38
+ conclusionMessage
39
+ }
40
+ """
@@ -0,0 +1,29 @@
1
+ from primitive.graphql.utility_fragments import operation_info_fragment
2
+
3
+ from .fragments import reservation_fragment
4
+
5
+ reservation_create_mutation = (
6
+ operation_info_fragment
7
+ + reservation_fragment
8
+ + """
9
+ mutation reservationCreate($input: ReservationCreateInput!) {
10
+ reservationCreate(input: $input) {
11
+ ...ReservationFragment
12
+ ...OperationInfoFragment
13
+ }
14
+ }
15
+ """
16
+ )
17
+
18
+ reservation_release_mutation = (
19
+ operation_info_fragment
20
+ + reservation_fragment
21
+ + """
22
+ mutation reservationRelease($input: ReservationReleaseInput!) {
23
+ reservationRelease(input: $input) {
24
+ ...ReservationFragment
25
+ ...OperationInfoFragment
26
+ }
27
+ }
28
+ """
29
+ )