Skip to content

Commit c89aba7

Browse files
olevskiPanaetius
andauthored
feat(cli): option to skip metadata update (#3025)
Co-authored-by: Ralf Grubenmann <[email protected]>
1 parent b1a803e commit c89aba7

File tree

9 files changed

+174
-44
lines changed

9 files changed

+174
-44
lines changed

renku/command/rerun.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@
2929
from renku.core.workflow.execute import execute_workflow_graph
3030

3131

32-
def rerun_command():
32+
def rerun_command(skip_metadata_update: bool):
3333
"""Recreate files generated by a sequence of ``run`` commands."""
34-
return Command().command(_rerun).require_migration().require_clean().with_database(write=True).with_commit()
34+
command = Command().command(_rerun).require_migration().require_clean()
35+
if skip_metadata_update:
36+
command = command.with_database(write=False)
37+
else:
38+
command = command.with_database(write=True).with_commit()
39+
return command
3540

3641

3742
@inject.autoparams()

renku/command/update.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@
3636
from renku.core.workflow.execute import execute_workflow_graph
3737

3838

39-
def update_command():
39+
def update_command(skip_metadata_update: bool):
4040
"""Update existing files by rerunning their outdated workflow."""
41-
return Command().command(_update).require_migration().require_clean().with_database(write=True).with_commit()
41+
command = Command().command(_update).require_migration().require_clean()
42+
if skip_metadata_update:
43+
command = command.with_database(write=False)
44+
else:
45+
command = command.with_database(write=True).with_commit()
46+
return command
4247

4348

4449
@inject.autoparams()

renku/command/workflow.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,29 @@ def workflow_outputs_command():
8282
return Command().command(workflow_outputs).require_migration().with_database(write=False)
8383

8484

85-
def execute_workflow_command():
85+
def execute_workflow_command(skip_metadata_update: bool):
8686
"""Command that executes a workflow."""
87-
return (
88-
Command().command(execute_workflow).require_migration().require_clean().with_database(write=True).with_commit()
89-
)
87+
command = Command().command(execute_workflow).require_migration().require_clean()
88+
if skip_metadata_update:
89+
command = command.with_database(write=False)
90+
else:
91+
command = command.with_database(write=True).with_commit()
92+
return command
9093

9194

9295
def visualize_graph_command():
9396
"""Execute the graph visualization command."""
9497
return Command().command(visualize_graph).require_migration().with_database(write=False)
9598

9699

97-
def iterate_workflow_command():
100+
def iterate_workflow_command(skip_metadata_update: bool):
98101
"""Command that executes several workflows given a set of variables."""
99-
return (
100-
Command().command(iterate_workflow).require_migration().require_clean().with_database(write=True).with_commit()
101-
)
102+
command = Command().command(iterate_workflow).require_migration().require_clean()
103+
if skip_metadata_update:
104+
command = command.with_database(write=False)
105+
else:
106+
command = command.with_database(write=True).with_commit()
107+
return command
102108

103109

104110
def revert_activity_command():

renku/ui/cli/rerun.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
If the output didn't change, it will be removed from git and re-added to ensure
5252
that the re-execution is properly tracked.
5353
54+
In some cases it may be desirable to avoid updating the renku metadata
55+
and to avoid committing this and any other change in the repository when the rerun
56+
command is used. If this is the case then you can pass the ``--skip-metadata-update``
57+
flag to ``renku rerun``.
5458
5559
.. cheatsheet::
5660
:group: Running
@@ -70,6 +74,7 @@
7074

7175
@click.command()
7276
@click.option("--dry-run", "-n", is_flag=True, default=False, help="Show a preview of plans that will be executed.")
77+
@click.option("--skip-metadata-update", is_flag=True, help="Do not update the metadata store for the execution.")
7378
@click.option(
7479
"--from",
7580
"sources",
@@ -90,7 +95,7 @@
9095
@click.option(
9196
"config", "-c", "--config", metavar="<config file>", help="YAML file containing configuration for the provider."
9297
)
93-
def rerun(dry_run, sources, paths, provider, config):
98+
def rerun(dry_run, skip_metadata_update, sources, paths, provider, config):
9499
"""Recreate files generated by a sequence of ``run`` commands."""
95100
from renku.command.format.activity import tabulate_activities
96101
from renku.command.rerun import rerun_command
@@ -99,7 +104,7 @@ def rerun(dry_run, sources, paths, provider, config):
99104

100105
try:
101106
result = (
102-
rerun_command()
107+
rerun_command(skip_metadata_update=skip_metadata_update)
103108
.with_communicator(communicator)
104109
.build()
105110
.execute(dry_run=dry_run, sources=sources, paths=paths, provider=provider, config=config)

renku/ui/cli/update.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@
7676
.. note:: If there were uncommitted changes then the command fails.
7777
Check :program:`git status` to see details.
7878
79+
In some cases it may be desirable to avoid updating the renku metadata
80+
and to avoid committing this and any other change in the repository when the update
81+
command is run. If this is the case then you can pass the ``--skip-metadata-update``
82+
flag to ``renku update``.
83+
7984
.. cheatsheet::
8085
:group: Running
8186
:command: $ renku update [--all] [<path>...]
@@ -167,7 +172,8 @@
167172
"config", "-c", "--config", metavar="<config file>", help="YAML file containing configuration for the provider."
168173
)
169174
@click.option("-i", "--ignore-deleted", is_flag=True, help="Ignore deleted paths.")
170-
def update(update_all, dry_run, paths, provider, config, ignore_deleted):
175+
@click.option("--skip-metadata-update", is_flag=True, help="Do not update the metadata store for the execution.")
176+
def update(update_all, dry_run, paths, provider, config, ignore_deleted, skip_metadata_update):
171177
"""Update existing files by rerunning their outdated workflow."""
172178
from renku.command.format.activity import tabulate_activities
173179
from renku.command.update import update_command
@@ -176,7 +182,7 @@ def update(update_all, dry_run, paths, provider, config, ignore_deleted):
176182

177183
try:
178184
result = (
179-
update_command()
185+
update_command(skip_metadata_update=skip_metadata_update)
180186
.with_communicator(communicator)
181187
.build()
182188
.execute(

renku/ui/cli/workflow.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@
149149
parameter <param-name>'s value.
150150
:extended:
151151
152+
In some cases it may be desirable to avoid updating the renku metadata
153+
and to avoid committing this and any other change in the repository when a workflow
154+
is executed. If this is the case then you can pass the ``--skip-metadata-update``
155+
flag to ``renku workflow execute``.
156+
152157
Iterate Plans
153158
*************
154159
@@ -212,6 +217,11 @@
212217
``10``, `20`` and ``30`` and the producing output files ``output_0.txt``,
213218
``output_1.txt`` and ``output_2.txt`` files in this order.
214219
220+
In some cases it may be desirable to avoid updating the renku metadata
221+
and to avoid committing this and any other change in the repository when a workflow
222+
is iterated through. If this is the case then you can pass the ``--skip-metadata-update``
223+
flag to ``renku workflow iterate``.
224+
215225
Exporting Plans
216226
***************
217227
@@ -1083,12 +1093,14 @@ def outputs(ctx, paths):
10831093
type=click.Path(exists=True, dir_okay=False),
10841094
help="YAML file containing parameter mappings to be used.",
10851095
)
1096+
@click.option("--skip-metadata-update", is_flag=True, help="Do not update the metadata store for the execution.")
10861097
@click.argument("name_or_id", required=True, shell_complete=_complete_workflows)
10871098
def execute(
10881099
provider,
10891100
config,
10901101
set_params,
10911102
values,
1103+
skip_metadata_update,
10921104
name_or_id,
10931105
):
10941106
"""Execute a given workflow."""
@@ -1097,7 +1109,7 @@ def execute(
10971109
communicator = ClickCallback()
10981110

10991111
result = (
1100-
execute_workflow_command()
1112+
execute_workflow_command(skip_metadata_update=skip_metadata_update)
11011113
.with_communicator(communicator)
11021114
.build()
11031115
.execute(
@@ -1196,6 +1208,7 @@ def visualize(sources, columns, exclude_files, ascii, interactive, no_color, pag
11961208

11971209

11981210
@workflow.command()
1211+
@click.option("--skip-metadata-update", is_flag=True, help="Do not update the metadata store for the execution.")
11991212
@click.option(
12001213
"mapping_path",
12011214
"--mapping",
@@ -1223,7 +1236,7 @@ def visualize(sources, columns, exclude_files, ascii, interactive, no_color, pag
12231236
@click.option("mappings", "-m", "--map", multiple=True, help="Mapping for a workflow parameter.")
12241237
@click.option("config", "-c", "--config", metavar="<config file>", help="YAML file containing config for the provider.")
12251238
@click.argument("name_or_id", required=True, shell_complete=_complete_workflows)
1226-
def iterate(name_or_id, mappings, mapping_path, dry_run, provider, config):
1239+
def iterate(name_or_id, mappings, mapping_path, dry_run, provider, config, skip_metadata_update):
12271240
"""Execute a workflow by iterating through a range of provided parameters."""
12281241
from renku.command.view_model.plan import PlanViewModel
12291242
from renku.command.workflow import iterate_workflow_command, show_workflow_command
@@ -1241,7 +1254,7 @@ def iterate(name_or_id, mappings, mapping_path, dry_run, provider, config):
12411254
_print_composite_plan(plan)
12421255

12431256
communicator = ClickCallback()
1244-
iterate_workflow_command().with_communicator(communicator).build().execute(
1257+
iterate_workflow_command(skip_metadata_update=skip_metadata_update).with_communicator(communicator).build().execute(
12451258
name_or_id=name_or_id,
12461259
mapping_path=mapping_path,
12471260
mappings=mappings,

tests/cli/test_rerun.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@
2525
import pytest
2626

2727
from renku.core.plugin.provider import available_workflow_providers
28+
from renku.infrastructure.gateway.activity_gateway import ActivityGateway
29+
from renku.infrastructure.gateway.plan_gateway import PlanGateway
2830
from renku.infrastructure.repository import Repository
2931
from renku.ui.cli import cli
3032
from tests.utils import format_result_exception, write_and_commit_file
3133

3234

3335
@pytest.mark.parametrize("provider", available_workflow_providers())
34-
def test_rerun(project, renku_cli, provider):
36+
@pytest.mark.parametrize("skip_metadata_update", [True, False])
37+
def test_rerun(project, client, client_database_injection_manager, renku_cli, provider, skip_metadata_update):
3538
"""Test rerun."""
3639
output = Path(project) / "output.txt"
3740

@@ -42,7 +45,19 @@ def test_rerun(project, renku_cli, provider):
4245
content = output.read_text().strip()
4346

4447
def rerun():
45-
assert 0 == renku_cli("rerun", "-p", provider, output).exit_code
48+
cmd = ["rerun", "-p", provider]
49+
if skip_metadata_update:
50+
cmd.append("--skip-metadata-update")
51+
cmd.append(output)
52+
assert 0 == renku_cli(*cmd).exit_code
53+
with client_database_injection_manager(client):
54+
plans = PlanGateway().get_all_plans()
55+
activities = ActivityGateway().get_all_activities()
56+
assert len(plans) == 1
57+
if skip_metadata_update:
58+
assert len(activities) == 1
59+
else:
60+
assert len(activities) > 1
4661
return output.read_text().strip()
4762

4863
for _ in range(10):

tests/cli/test_update.py

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333

3434

3535
@pytest.mark.parametrize("provider", available_workflow_providers())
36-
def test_update(runner, client, renku_cli, client_database_injection_manager, provider):
36+
@pytest.mark.parametrize("skip_metadata_update", [True, False])
37+
def test_update(runner, client, renku_cli, client_database_injection_manager, provider, skip_metadata_update):
3738
"""Test output is updated when source changes."""
3839
source = os.path.join(client.path, "source.txt")
3940
output = os.path.join(client.path, "output.txt")
@@ -45,17 +46,22 @@ def test_update(runner, client, renku_cli, client_database_injection_manager, pr
4546

4647
write_and_commit_file(client.repository, source, "changed content")
4748

48-
exit_code, activity = renku_cli("update", "-p", provider, "--all")
49+
cmd = ["update", "-p", provider, "--all"]
50+
if skip_metadata_update:
51+
cmd.append("--skip-metadata-update")
52+
exit_code, activity = renku_cli(*cmd)
4953

5054
assert 0 == exit_code
51-
plan = activity.association.plan
52-
assert previous_activity.association.plan.id == plan.id
53-
assert isinstance(plan, Plan)
54-
5555
assert "changed content" == Path(output).read_text()
5656

57-
result = runner.invoke(cli, ["status"])
58-
assert 0 == result.exit_code, format_result_exception(result)
57+
if skip_metadata_update:
58+
assert activity is None
59+
else:
60+
plan = activity.association.plan
61+
assert previous_activity.association.plan.id == plan.id
62+
assert isinstance(plan, Plan)
63+
result = runner.invoke(cli, ["status"])
64+
assert 0 == result.exit_code, format_result_exception(result)
5965

6066
with client_database_injection_manager(client):
6167
activity_gateway = ActivityGateway()
@@ -64,12 +70,20 @@ def test_update(runner, client, renku_cli, client_database_injection_manager, pr
6470
# NOTE: No ActivityCollection is created if update include only one activity
6571
assert [] == activity_collections
6672

73+
if skip_metadata_update:
74+
assert len(activity_gateway.get_all_activities()) == 1
75+
else:
76+
assert len(activity_gateway.get_all_activities()) == 2
77+
6778
result = runner.invoke(cli, ["graph", "export", "--format", "json-ld", "--strict"])
6879
assert 0 == result.exit_code, format_result_exception(result)
6980

7081

7182
@pytest.mark.parametrize("provider", available_workflow_providers())
72-
def test_update_multiple_steps(runner, client, renku_cli, client_database_injection_manager, provider):
83+
@pytest.mark.parametrize("skip_metadata_update", [True, False])
84+
def test_update_multiple_steps(
85+
runner, client, renku_cli, client_database_injection_manager, provider, skip_metadata_update
86+
):
7387
"""Test update in a multi-step workflow."""
7488
source = os.path.join(client.path, "source.txt")
7589
intermediate = os.path.join(client.path, "intermediate.txt")
@@ -84,27 +98,37 @@ def test_update_multiple_steps(runner, client, renku_cli, client_database_inject
8498

8599
write_and_commit_file(client.repository, source, "changed content")
86100

87-
exit_code, activities = renku_cli("update", "-p", provider, "--all")
101+
cmd = ["update", "-p", provider, "--all"]
102+
if skip_metadata_update:
103+
cmd.append("--skip-metadata-update")
104+
exit_code, activities = renku_cli(*cmd)
88105

89106
assert 0 == exit_code
90-
plans = [a.association.plan for a in activities]
91-
assert 2 == len(plans)
92-
assert isinstance(plans[0], Plan)
93-
assert isinstance(plans[1], Plan)
94-
assert {p.id for p in plans} == {activity1.association.plan.id, activity2.association.plan.id}
95-
96107
assert "changed content" == Path(intermediate).read_text()
97108
assert "changed content" == Path(output).read_text()
98109

99-
result = runner.invoke(cli, ["status"])
100-
assert 0 == result.exit_code, format_result_exception(result)
110+
if skip_metadata_update:
111+
assert activities is None
112+
else:
113+
plans = [a.association.plan for a in activities]
114+
assert 2 == len(plans)
115+
assert isinstance(plans[0], Plan)
116+
assert isinstance(plans[1], Plan)
117+
assert {p.id for p in plans} == {activity1.association.plan.id, activity2.association.plan.id}
118+
result = runner.invoke(cli, ["status"])
119+
assert 0 == result.exit_code, format_result_exception(result)
101120

102121
with client_database_injection_manager(client):
103122
activity_gateway = ActivityGateway()
104123
activity_collections = activity_gateway.get_all_activity_collections()
105124

106-
assert 1 == len(activity_collections)
107-
assert {a.id for a in activities} == {a.id for a in activity_collections[0].activities}
125+
all_activities = activity_gateway.get_all_activities()
126+
if skip_metadata_update:
127+
assert len(all_activities) == 2
128+
else:
129+
assert 1 == len(activity_collections)
130+
assert {a.id for a in activities} == {a.id for a in activity_collections[0].activities}
131+
assert len(all_activities) == 4
108132

109133

110134
@pytest.mark.parametrize("provider", available_workflow_providers())

0 commit comments

Comments
 (0)