Skip to content

Commit 2375d9a

Browse files
committed
feat: add cost_optimization_features to job definitions
Add support for cost_optimization_features field (state_aware_orchestration, efficient_testing) so dbt Fusion users can configure cost optimization natively in YAML job definitions. Closes #196
1 parent ef8de19 commit 2375d9a

7 files changed

Lines changed: 125 additions & 2 deletions

File tree

docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
To see the details of all changes, head to the GitHub repo
33

4+
### 1.16
5+
6+
- Add support for `cost_optimization_features` in job definitions. Valid values are `state_aware_orchestration` and `efficient_testing`. This allows for dbt users on the Fusion engine to configure cost optimization natively in their YAML job definitions.
7+
48
### 1.14
59

610
- Add applied job IDs to `sync --json` output. The JSON now includes an `applied` section with `job_id` for each operation and an `apply_success` flag. See [JSON output](advanced_config/json_output.md) for details.

example_jobs_file/jobs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ jobs:
2626
git_provider_webhook: false
2727
github_webhook: false
2828
schedule: true
29+
cost_optimization_features:
30+
- state_aware_orchestration
2931

3032
job2:
3133
account_id: 43791

src/dbt_jobs_as_code/schemas/job.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ class JobDefinition(BaseModel):
110110
json_schema_extra={"enum": ["scheduled", "merge", "ci", "other"]},
111111
default="scheduled",
112112
)
113+
cost_optimization_features: Optional[List[str]] = Field(
114+
default=None,
115+
json_schema_extra={
116+
"items": {"enum": ["state_aware_orchestration", "efficient_testing"]},
117+
},
118+
)
113119
triggers_on_draft_pr: bool = False
114120
job_completion_trigger_condition: Optional[JobCompletionTriggerCondition] = None
115121
custom_environment_variables: List[CustomEnvironmentVariable] = Field(
@@ -270,9 +276,7 @@ class JobMissingFields(JobDefinition):
270276
# when adding fields we also need to update the test for pytest
271277

272278
# TODO: Add to JobDefinition model when the feature is out
273-
integration_id: Optional[int] = None
274279
force_node_selection: Optional[bool] = True
275-
cost_optimization_features: list[str]
276280

277281
# Unneeded read-only fields
278282
raw_dbt_version: Optional[str] = None

src/dbt_jobs_as_code/schemas/load_job_schema.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,27 @@
329329
"title": "Job Type",
330330
"type": "string"
331331
},
332+
"cost_optimization_features": {
333+
"anyOf": [
334+
{
335+
"items": {
336+
"type": "string"
337+
},
338+
"type": "array"
339+
},
340+
{
341+
"type": "null"
342+
}
343+
],
344+
"default": null,
345+
"items": {
346+
"enum": [
347+
"state_aware_orchestration",
348+
"efficient_testing"
349+
]
350+
},
351+
"title": "Cost Optimization Features"
352+
},
332353
"triggers_on_draft_pr": {
333354
"default": false,
334355
"title": "Triggers On Draft Pr",

tests/exporter/test_export.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def test_export_jobs_yml(capsys):
7070
run_compare_changes: false
7171
compare_changes_flags: --select state:modified
7272
job_type: scheduled
73+
cost_optimization_features:
7374
triggers_on_draft_pr: false
7475
job_completion_trigger_condition:
7576
custom_environment_variables: []

tests/loader/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def expected_config_dict():
206206
"job1": {
207207
"account_id": 43791,
208208
"compare_changes_flags": "--select state:modified",
209+
"cost_optimization_features": None,
209210
"custom_environment_variables": [],
210211
"dbt_version": None,
211212
"deferring_environment_id": None,
@@ -248,6 +249,7 @@ def expected_config_dict():
248249
"job2": {
249250
"account_id": 43791,
250251
"compare_changes_flags": "--select state:modified",
252+
"cost_optimization_features": None,
251253
"custom_environment_variables": [
252254
{
253255
"display_value": None,

tests/schemas/test_job.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,92 @@ def test_json_schema_schedule_accepted_for_all_types(self, json_schema, job_type
239239
"""Providing schedule is always valid regardless of job_type."""
240240
instance = self._config_instance(job_type=job_type, include_schedule=True)
241241
validate(instance=instance, schema=json_schema)
242+
243+
244+
class TestCostOptimizationFeatures:
245+
"""Tests for cost_optimization_features field on JobDefinition."""
246+
247+
def test_pydantic_defaults_to_none(self):
248+
job = JobDefinition(**{**BASE_JOB_DATA, "schedule": {"cron": "0 0 * * *"}})
249+
assert job.cost_optimization_features is None
250+
251+
def test_pydantic_accepts_valid_features(self):
252+
job = JobDefinition(
253+
**{
254+
**BASE_JOB_DATA,
255+
"schedule": {"cron": "0 0 * * *"},
256+
"cost_optimization_features": ["state_aware_orchestration"],
257+
}
258+
)
259+
assert job.cost_optimization_features == ["state_aware_orchestration"]
260+
261+
def test_pydantic_accepts_multiple_features(self):
262+
job = JobDefinition(
263+
**{
264+
**BASE_JOB_DATA,
265+
"schedule": {"cron": "0 0 * * *"},
266+
"cost_optimization_features": [
267+
"state_aware_orchestration",
268+
"efficient_testing",
269+
],
270+
}
271+
)
272+
assert job.cost_optimization_features == [
273+
"state_aware_orchestration",
274+
"efficient_testing",
275+
]
276+
277+
def test_pydantic_accepts_empty_list(self):
278+
job = JobDefinition(
279+
**{
280+
**BASE_JOB_DATA,
281+
"schedule": {"cron": "0 0 * * *"},
282+
"cost_optimization_features": [],
283+
}
284+
)
285+
assert job.cost_optimization_features == []
286+
287+
def test_payload_includes_cost_optimization_features(self):
288+
job = JobDefinition(
289+
**{
290+
**BASE_JOB_DATA,
291+
"schedule": {"cron": "0 0 * * *"},
292+
"cost_optimization_features": ["state_aware_orchestration"],
293+
}
294+
)
295+
payload = json.loads(job.to_payload())
296+
assert payload["cost_optimization_features"] == ["state_aware_orchestration"]
297+
298+
def test_payload_includes_null_when_not_set(self):
299+
job = JobDefinition(**{**BASE_JOB_DATA, "schedule": {"cron": "0 0 * * *"}})
300+
payload = json.loads(job.to_payload())
301+
assert payload["cost_optimization_features"] is None
302+
303+
@pytest.fixture
304+
def json_schema(self):
305+
return json.loads(generate_config_schema())
306+
307+
def test_json_schema_accepts_valid_features(self, json_schema):
308+
instance = {
309+
"jobs": {
310+
"test_job": {
311+
**BASE_JOB_DATA,
312+
"schedule": {"cron": "0 0 * * *"},
313+
"cost_optimization_features": ["state_aware_orchestration"],
314+
}
315+
}
316+
}
317+
validate(instance=instance, schema=json_schema)
318+
319+
def test_json_schema_rejects_invalid_feature(self, json_schema):
320+
instance = {
321+
"jobs": {
322+
"test_job": {
323+
**BASE_JOB_DATA,
324+
"schedule": {"cron": "0 0 * * *"},
325+
"cost_optimization_features": ["not_a_real_feature"],
326+
}
327+
}
328+
}
329+
with pytest.raises(JsonSchemaValidationError):
330+
validate(instance=instance, schema=json_schema)

0 commit comments

Comments
 (0)