Skip to content

Commit 4239bcd

Browse files
authored
Merge pull request #124 from dbt-labs/feature/import-reuse-id
Link jobs to existing ID when importing jobs
2 parents d588486 + f542281 commit 4239bcd

3 files changed

Lines changed: 78 additions & 5 deletions

File tree

src/dbt_jobs_as_code/exporter/export.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ def export_jobs_yml(jobs: list[JobDefinition], include_linked_id: bool = False):
1010

1111
export_yml = {"jobs": {}}
1212
for id, cloud_job in enumerate(jobs):
13-
export_yml["jobs"][f"import_{id + 1}"] = cloud_job.to_load_format(include_linked_id)
13+
yaml_key = cloud_job.identifier if cloud_job.identifier else f"import_{id + 1}"
14+
export_yml["jobs"][yaml_key] = cloud_job.to_load_format(include_linked_id)
1415

1516
print(
1617
"# yaml-language-server: $schema=https://raw.githubusercontent.com/dbt-labs/dbt-jobs-as-code/main/src/dbt_jobs_as_code/schemas/load_job_schema.json"

src/dbt_jobs_as_code/loader/load.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def load_job_configuration(config_files: List[str], vars_file: Optional[List[str
2323
else:
2424
config = _load_yaml_no_template(config_files)
2525

26-
if not config["jobs"]:
26+
if config.get("jobs", {}) == {}:
2727
return Config(jobs={})
2828

2929
date_config = [job.get("schedule", {}).get("date", None) for job in config["jobs"].values()]
@@ -61,7 +61,7 @@ def _load_yaml_no_template(config_files: List[str]) -> dict:
6161
config = yaml.safe_load(config_string)
6262
if config:
6363
# Merge the jobs from each file into combined_config
64-
if "jobs" in config:
64+
if config.get("jobs", {}) != {}:
6565
if "jobs" not in combined_config:
6666
combined_config["jobs"] = {}
6767
combined_config["jobs"].update(config["jobs"])

tests/exporter/test_export.py

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import json
22

3+
import pytest
4+
from jsonschema import validate
5+
from ruamel.yaml import YAML
6+
37
from dbt_jobs_as_code.exporter.export import export_jobs_yml
48
from dbt_jobs_as_code.schemas.common_types import (
59
Date,
@@ -10,8 +14,22 @@
1014
Triggers,
1115
)
1216
from dbt_jobs_as_code.schemas.job import JobDefinition
13-
from jsonschema import validate
14-
from ruamel.yaml import YAML
17+
18+
19+
@pytest.fixture
20+
def base_job_definition():
21+
return JobDefinition(
22+
account_id=1,
23+
project_id=1,
24+
environment_id=1,
25+
name="Test Job",
26+
settings={},
27+
run_generate_sources=False,
28+
execute_steps=[],
29+
generate_docs=False,
30+
schedule={"cron": "0 14 * * 0,1,2,3,4,5,6"},
31+
triggers={},
32+
)
1533

1634

1735
def test_export_jobs_yml(capsys):
@@ -99,3 +117,57 @@ def test_export_jobs_yml(capsys):
99117
yaml = YAML(typ="safe")
100118
yaml_data = yaml.load(captured.out.strip())
101119
validate(instance=yaml_data, schema=json.loads(schema))
120+
121+
122+
def test_export_jobs_yml_with_identifier(base_job_definition, capsys):
123+
# Create a job with identifier
124+
job_with_identifier = base_job_definition.model_copy()
125+
job_with_identifier.identifier = "existing_identifier"
126+
127+
# Create a job without identifier
128+
job_without_identifier = base_job_definition.model_copy()
129+
130+
jobs = [job_with_identifier, job_without_identifier]
131+
132+
# Export jobs and capture output
133+
export_jobs_yml(jobs)
134+
captured = capsys.readouterr()
135+
136+
# Parse the YAML output (skipping the first two lines which contain the schema)
137+
yaml = YAML()
138+
exported_jobs = yaml.load("\n".join(captured.out.split("\n")[2:]))
139+
140+
# Verify the job keys
141+
assert "existing_identifier" in exported_jobs["jobs"]
142+
assert "import_2" in exported_jobs["jobs"]
143+
144+
# Verify the job contents
145+
assert exported_jobs["jobs"]["existing_identifier"]["name"] == "Test Job"
146+
assert exported_jobs["jobs"]["import_2"]["name"] == "Test Job"
147+
148+
149+
def test_export_jobs_yml_with_linked_id(base_job_definition, capsys):
150+
# Create a job with both identifier and id
151+
job = base_job_definition.model_copy()
152+
job.identifier = "test_identifier"
153+
job.id = 123
154+
155+
# Export with include_linked_id=True
156+
export_jobs_yml([job], include_linked_id=True)
157+
captured = capsys.readouterr()
158+
159+
yaml = YAML()
160+
exported_jobs = yaml.load("\n".join(captured.out.split("\n")[2:]))
161+
162+
# Verify linked_id is included and matches the id
163+
assert exported_jobs["jobs"]["test_identifier"]["linked_id"] == 123
164+
165+
# Export with include_linked_id=False
166+
export_jobs_yml([job], include_linked_id=False)
167+
captured = capsys.readouterr()
168+
169+
yaml = YAML()
170+
exported_jobs = yaml.load("\n".join(captured.out.split("\n")[2:]))
171+
172+
# Verify linked_id is not included
173+
assert "linked_id" not in exported_jobs["jobs"]["test_identifier"]

0 commit comments

Comments
 (0)