Skip to content

Commit 44d6d4c

Browse files
Add run_tasks_integration model
1 parent c21a8ef commit 44d6d4c

1 file changed

Lines changed: 156 additions & 0 deletions

File tree

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"""Run Tasks Integration models for python-tfe.
2+
3+
This module contains models for run tasks integration callback functionality.
4+
"""
5+
6+
from __future__ import annotations
7+
8+
from typing import Any
9+
10+
from .task_result import TaskResultStatus
11+
12+
13+
class TaskResultTag:
14+
"""Tag to enrich outcomes display in TFC/TFE.
15+
16+
API Documentation:
17+
https://developer.hashicorp.com/terraform/enterprise/api-docs/run-tasks/run-tasks-integration#severity-and-status-tags
18+
"""
19+
20+
def __init__(self, label: str, level: str | None = None):
21+
"""Initialize a task result tag.
22+
23+
Args:
24+
label: The label for the tag
25+
level: Optional severity level (error, warning, info)
26+
"""
27+
self.label = label
28+
self.level = level
29+
30+
def to_dict(self) -> dict[str, Any]:
31+
"""Convert to dictionary for JSON serialization."""
32+
result = {"label": self.label}
33+
if self.level:
34+
result["level"] = self.level
35+
return result
36+
37+
38+
class TaskResultOutcome:
39+
"""Detailed run task outcome for improved visibility in TFC/TFE UI.
40+
41+
API Documentation:
42+
https://developer.hashicorp.com/terraform/enterprise/api-docs/run-tasks/run-tasks-integration#outcomes-payload-body
43+
"""
44+
45+
def __init__(
46+
self,
47+
outcome_id: str | None = None,
48+
description: str | None = None,
49+
body: str | None = None,
50+
url: str | None = None,
51+
tags: dict[str, list[TaskResultTag]] | None = None,
52+
):
53+
"""Initialize a task result outcome.
54+
55+
Args:
56+
outcome_id: Unique identifier for the outcome
57+
description: Brief description of the outcome
58+
body: Detailed body content (supports markdown)
59+
url: URL to view more details
60+
tags: Dictionary of tag categories to lists of tags
61+
"""
62+
self.outcome_id = outcome_id
63+
self.description = description
64+
self.body = body
65+
self.url = url
66+
self.tags = tags or {}
67+
68+
def to_dict(self) -> dict[str, Any]:
69+
"""Convert to dictionary for JSON:API serialization."""
70+
result: dict[str, Any] = {"type": "task-result-outcomes", "attributes": {}}
71+
72+
if self.outcome_id:
73+
result["attributes"]["outcome-id"] = self.outcome_id
74+
if self.description:
75+
result["attributes"]["description"] = self.description
76+
if self.body:
77+
result["attributes"]["body"] = self.body
78+
if self.url:
79+
result["attributes"]["url"] = self.url
80+
if self.tags:
81+
result["attributes"]["tags"] = {
82+
key: [tag.to_dict() for tag in tags] for key, tags in self.tags.items()
83+
}
84+
85+
return result
86+
87+
88+
class TaskResultCallbackOptions:
89+
"""Options for sending task result callback to TFC/TFE.
90+
91+
API Documentation:
92+
https://developer.hashicorp.com/terraform/enterprise/api-docs/run-tasks/run-tasks-integration#request-body-1
93+
"""
94+
95+
def __init__(
96+
self,
97+
status: str,
98+
message: str | None = None,
99+
url: str | None = None,
100+
outcomes: list[TaskResultOutcome] | None = None,
101+
):
102+
"""Initialize callback options.
103+
104+
Args:
105+
status: Task result status (passed, failed, running)
106+
message: Optional message about the task result
107+
url: Optional URL to view detailed results
108+
outcomes: Optional list of detailed outcomes
109+
"""
110+
self.status = status
111+
self.message = message
112+
self.url = url
113+
self.outcomes = outcomes or []
114+
115+
def validate(self) -> None:
116+
"""Validate the callback options.
117+
118+
Only passed, failed, and running statuses are allowed for callbacks.
119+
pending and errored are not valid callback statuses per TFC/TFE API.
120+
121+
Raises:
122+
InvalidTaskResultsCallbackStatus: If status is not valid for callbacks
123+
"""
124+
from ..errors import InvalidTaskResultsCallbackStatus
125+
126+
valid_statuses = [
127+
TaskResultStatus.PASSED.value,
128+
TaskResultStatus.FAILED.value,
129+
TaskResultStatus.RUNNING.value,
130+
]
131+
if self.status not in valid_statuses:
132+
raise InvalidTaskResultsCallbackStatus(
133+
f"Invalid task result status: {self.status}. "
134+
f"Must be one of: {', '.join(valid_statuses)}"
135+
)
136+
137+
def to_dict(self) -> dict[str, Any]:
138+
"""Convert to dictionary for JSON:API format."""
139+
data: dict[str, Any] = {
140+
"type": "task-results",
141+
"attributes": {
142+
"status": self.status,
143+
},
144+
}
145+
146+
if self.message:
147+
data["attributes"]["message"] = self.message
148+
if self.url:
149+
data["attributes"]["url"] = self.url
150+
151+
if self.outcomes:
152+
data["relationships"] = {
153+
"outcomes": {"data": [outcome.to_dict() for outcome in self.outcomes]}
154+
}
155+
156+
return {"data": data}

0 commit comments

Comments
 (0)