Skip to content

Commit b1cd014

Browse files
Keep order of tasks in the README notebook (#286)
Resolves #285
1 parent cd033d5 commit b1cd014

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

src/databricks/labs/ucx/framework/tasks.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
@dataclass
1414
class Task:
15+
task_id: int
1516
workflow: str
1617
name: str
1718
doc: str
@@ -54,6 +55,7 @@ def wrapper(*args, **kwargs):
5455
raise SyntaxError(msg)
5556

5657
_TASKS[func.__name__] = Task(
58+
task_id=len(_TASKS),
5759
workflow=workflow,
5860
name=func.__name__,
5961
doc=func.__doc__,

src/databricks/labs/ucx/install.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,21 +263,37 @@ def _create_jobs(self):
263263
self._create_readme()
264264
self._create_debug(remote_wheel)
265265

266+
@staticmethod
267+
def _sorted_tasks() -> list[Task]:
268+
return sorted(_TASKS.values(), key=lambda x: x.task_id)
269+
270+
@classmethod
271+
def _step_list(cls) -> list[str]:
272+
step_list = []
273+
for task in cls._sorted_tasks():
274+
if task.workflow not in step_list:
275+
step_list.append(task.workflow)
276+
return step_list
277+
266278
def _create_readme(self):
267279
md = [
268280
"# UCX - The Unity Catalog Migration Assistant",
269281
f'To troubleshoot, see [debug notebook]({self._notebook_link(f"{self._install_folder}/DEBUG.py")}).\n',
270282
"Here are the URL and descriptions of jobs that trigger's various stages of migration.",
271283
"All jobs are defined with necessary cluster configurations and DBR versions.",
272284
]
273-
for step_name, job_id in self._deployed_steps.items():
285+
for step_name in self._step_list():
286+
if step_name not in self._deployed_steps:
287+
logger.warning(f"Skipping step '{step_name}' since it was not deployed.")
288+
continue
289+
job_id = self._deployed_steps[step_name]
274290
dashboard_link = ""
275291
if step_name in self._dashboards:
276292
dashboard_link = f"{self._ws.config.host}/sql/dashboards/{self._dashboards[step_name]}"
277293
dashboard_link = f" (see [{step_name} dashboard]({dashboard_link}) after finish)"
278294
job_link = f"[{self._name(step_name)}]({self._ws.config.host}#job/{job_id})"
279295
md.append(f"## {job_link}{dashboard_link}\n")
280-
for t in _TASKS.values():
296+
for t in self._sorted_tasks():
281297
if t.workflow != step_name:
282298
continue
283299
doc = re.sub(r"\s+", " ", t.doc)

tests/unit/test_install.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,56 @@ def test_choices_happy(mocker):
220220
mocker.patch("builtins.input", return_value="1")
221221
res = install._choice("foo", ["a", "b"])
222222
assert "b" == res
223+
224+
225+
def test_step_list(mocker):
226+
ws = mocker.Mock()
227+
from databricks.labs.ucx.framework.tasks import Task
228+
229+
tasks = [
230+
Task(task_id=0, workflow="wl_1", name="n3", doc="d3", fn=lambda: None),
231+
Task(task_id=1, workflow="wl_2", name="n2", doc="d2", fn=lambda: None),
232+
Task(task_id=2, workflow="wl_1", name="n1", doc="d1", fn=lambda: None),
233+
]
234+
235+
with mocker.patch.object(WorkspaceInstaller, attribute="_sorted_tasks", return_value=tasks):
236+
install = WorkspaceInstaller(ws)
237+
steps = install._step_list()
238+
assert len(steps) == 2
239+
assert steps[0] == "wl_1" and steps[1] == "wl_2"
240+
241+
242+
def test_create_readme(mocker):
243+
mocker.patch("builtins.input", return_value="yes")
244+
webbrowser_open = mocker.patch("webbrowser.open")
245+
ws = mocker.Mock()
246+
247+
ws.current_user.me = lambda: iam.User(user_name="[email protected]", groups=[iam.ComplexValue(display="admins")])
248+
ws.config.host = "https://foo"
249+
config_bytes = yaml.dump(WorkspaceConfig(inventory_database="a", groups=GroupsConfig(auto=True)).as_dict()).encode(
250+
"utf8"
251+
)
252+
ws.workspace.download = lambda _: io.BytesIO(config_bytes)
253+
254+
from databricks.labs.ucx.framework.tasks import Task
255+
256+
tasks = [
257+
Task(task_id=0, workflow="wl_1", name="n3", doc="d3", fn=lambda: None),
258+
Task(task_id=1, workflow="wl_2", name="n2", doc="d2", fn=lambda: None),
259+
Task(task_id=2, workflow="wl_1", name="n1", doc="d1", fn=lambda: None),
260+
]
261+
262+
with mocker.patch.object(WorkspaceInstaller, attribute="_sorted_tasks", return_value=tasks):
263+
install = WorkspaceInstaller(ws)
264+
install._deployed_steps = {"wl_1": 1, "wl_2": 2}
265+
install._create_readme()
266+
267+
webbrowser_open.assert_called_with("https://foo/#workspace/Users/[email protected]/.ucx/README.py")
268+
269+
_, args, kwargs = ws.mock_calls[0]
270+
assert args[0] == "/Users/[email protected]/.ucx/README.py"
271+
272+
import re
273+
274+
p = re.compile(".*wl_1.*n3.*n1.*wl_2.*n2.*")
275+
assert p.match(str(args[1]))

0 commit comments

Comments
 (0)