Skip to content

Commit 56f64ed

Browse files
committed
add single package support for auto_tick, clean up dry run option
1 parent ada4150 commit 56f64ed

File tree

5 files changed

+112
-24
lines changed

5 files changed

+112
-24
lines changed

conda_forge_tick/auto_tick.py

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import traceback
1010
import typing
1111
from dataclasses import dataclass
12-
from typing import Literal, cast
12+
from typing import AnyStr, Literal, cast
1313

1414
from .models.pr_info import PullRequestInfoSpecial
1515
from .models.pr_json import PullRequestData, PullRequestState
@@ -46,6 +46,7 @@
4646
)
4747
from conda_forge_tick.lazy_json_backends import (
4848
LazyJson,
49+
does_key_exist_in_hashmap,
4950
get_all_keys_for_hashmap,
5051
lazy_json_transaction,
5152
remove_key_for_hashmap,
@@ -662,7 +663,7 @@ def run(
662663
return migration_run_data["migrate_return_value"], pr_lazy_json
663664

664665

665-
def _compute_time_per_migrator(mctx, migrators):
666+
def _compute_time_per_migrator(migrators):
666667
# we weight each migrator by the number of available nodes to migrate
667668
num_nodes = []
668669
for migrator in tqdm.tqdm(migrators, ncols=80, desc="computing time per migrator"):
@@ -918,7 +919,26 @@ def _is_migrator_done(_mg_start, good_prs, time_per, pr_limit):
918919
return False
919920

920921

921-
def _run_migrator(migrator, mctx, temp, time_per, git_backend: GitPlatformBackend):
922+
def _run_migrator(
923+
migrator: Migrator,
924+
mctx: MigratorSessionContext,
925+
temp: list[AnyStr],
926+
time_per: float,
927+
git_backend: GitPlatformBackend,
928+
package: str | None = None,
929+
) -> int:
930+
"""
931+
Run a migrator.
932+
933+
:param migrator: The migrator to run.
934+
:param mctx: The migrator session context.
935+
:param temp: The list of temporary files.
936+
:param time_per: The time limit of this migrator.
937+
:param git_backend: The GitPlatformBackend instance to use.
938+
:param package: The package to update, if None, all packages are updated.
939+
940+
:return: The number of "good" PRs created by the migrator.
941+
"""
922942
_mg_start = time.time()
923943

924944
migrator_name = get_migrator_name(migrator)
@@ -940,6 +960,14 @@ def _run_migrator(migrator, mctx, temp, time_per, git_backend: GitPlatformBacken
940960

941961
possible_nodes = list(migrator.order(effective_graph, mctx.graph))
942962

963+
if package:
964+
if package not in possible_nodes:
965+
logger.warning(
966+
f"Package {package} is not a candidate for migration of {migrator_name}"
967+
)
968+
return 0
969+
possible_nodes = [package]
970+
943971
# version debugging info
944972
if isinstance(migrator, Version):
945973
print("possible version migrations:", flush=True)
@@ -1084,18 +1112,26 @@ def _setup_limits():
10841112
resource.setrlimit(resource.RLIMIT_AS, (limit_int, limit_int))
10851113

10861114

1087-
def _update_nodes_with_bot_rerun(gx: nx.DiGraph):
1088-
"""Go through all the open PRs and check if they are rerun"""
1115+
def _update_nodes_with_bot_rerun(gx: nx.DiGraph, package: str | None = None):
1116+
"""
1117+
Go through all the open PRs and check if they are rerun
1118+
1119+
:param gx: the dependency graph
1120+
:param package: the package to update, if None, all packages are updated
1121+
"""
10891122

10901123
print("processing bot-rerun labels", flush=True)
10911124

1092-
for i, (name, node) in enumerate(gx.nodes.items()):
1125+
nodes = gx.nodes.items() if not package else [(package, gx.nodes[package])]
1126+
1127+
for i, (name, node) in nodes:
10931128
# logger.info(
10941129
# f"node: {i} memory usage: "
10951130
# f"{psutil.Process().memory_info().rss // 1024 ** 2}MB",
10961131
# )
10971132
with node["payload"] as payload:
10981133
if payload.get("archived", False):
1134+
logger.debug(f"skipping archived package {name}")
10991135
continue
11001136
with payload["pr_info"] as pri, payload["version_pr_info"] as vpri:
11011137
# reset bad
@@ -1145,12 +1181,21 @@ def _filter_ignored_versions(attrs, version):
11451181
return version
11461182

11471183

1148-
def _update_nodes_with_new_versions(gx):
1149-
"""Updates every node with it's new version (when available)"""
1184+
def _update_nodes_with_new_versions(gx: nx.DiGraph, package: str | None = None):
1185+
"""
1186+
Updates every node with its new version (when available)
1187+
1188+
:param gx: the dependency graph
1189+
:param package: the package to update, if None, all packages are updated
1190+
"""
11501191

11511192
print("updating nodes with new versions", flush=True)
11521193

1153-
version_nodes = get_all_keys_for_hashmap("versions")
1194+
if package and not does_key_exist_in_hashmap("versions", package):
1195+
logger.warning(f"Package {package} not found in versions hashmap")
1196+
return
1197+
1198+
version_nodes = get_all_keys_for_hashmap("versions") if not package else [package]
11541199

11551200
for node in version_nodes:
11561201
version_data = LazyJson(f"versions/{node}.json").data
@@ -1176,13 +1221,35 @@ def _update_nodes_with_new_versions(gx):
11761221
vpri["new_version"] = version_from_data
11771222

11781223

1179-
def _remove_closed_pr_json():
1224+
def _remove_closed_pr_json(package: str | None = None):
1225+
"""
1226+
Remove the pull request information for closed PRs.
1227+
1228+
:param package: The package to remove the PR information for. If None, all PR information is removed. If you pass
1229+
a package, closed pr_json files are not removed because this would require iterating all pr_json files.
1230+
"""
11801231
print("collapsing closed PR json", flush=True)
11811232

1233+
if package:
1234+
pr_info_nodes = (
1235+
[package] if does_key_exist_in_hashmap("pr_info", package) else []
1236+
)
1237+
version_pr_info_nodes = (
1238+
[package] if does_key_exist_in_hashmap("version_pr_info", package) else []
1239+
)
1240+
1241+
if not pr_info_nodes:
1242+
logger.warning(f"Package {package} not found in pr_info hashmap")
1243+
if not version_pr_info_nodes:
1244+
logger.warning(f"Package {package} not found in version_pr_info hashmap")
1245+
else:
1246+
pr_info_nodes = get_all_keys_for_hashmap("pr_info")
1247+
version_pr_info_nodes = get_all_keys_for_hashmap("version_pr_info")
1248+
11821249
# first we go from nodes to pr json and update the pr info and remove the data
11831250
name_nodes = [
1184-
("pr_info", get_all_keys_for_hashmap("pr_info")),
1185-
("version_pr_info", get_all_keys_for_hashmap("version_pr_info")),
1251+
("pr_info", pr_info_nodes),
1252+
("version_pr_info", version_pr_info_nodes),
11861253
]
11871254
for name, nodes in name_nodes:
11881255
for node in nodes:
@@ -1215,6 +1282,11 @@ def _remove_closed_pr_json():
12151282

12161283
# at this point, any json blob referenced in the pr info is state != closed
12171284
# so we can remove anything that is empty or closed
1285+
if package:
1286+
logger.info(
1287+
"Since you requested a run for a specific package, we are not removing closed pr_json files."
1288+
)
1289+
return
12181290
nodes = get_all_keys_for_hashmap("pr_json")
12191291
for node in nodes:
12201292
pr = LazyJson(f"pr_json/{node}.json")
@@ -1225,22 +1297,22 @@ def _remove_closed_pr_json():
12251297
)
12261298

12271299

1228-
def _update_graph_with_pr_info():
1229-
_remove_closed_pr_json()
1300+
def _update_graph_with_pr_info(package: str | None = None):
1301+
_remove_closed_pr_json(package)
12301302
gx = load_existing_graph()
1231-
_update_nodes_with_bot_rerun(gx)
1232-
_update_nodes_with_new_versions(gx)
1303+
_update_nodes_with_bot_rerun(gx, package)
1304+
_update_nodes_with_new_versions(gx, package)
12331305
dump_graph(gx)
12341306

12351307

1236-
def main(ctx: CliContext) -> None:
1308+
def main(ctx: CliContext, package: str | None = None) -> None:
12371309
global START_TIME
12381310
START_TIME = time.time()
12391311

12401312
_setup_limits()
12411313

12421314
with fold_log_lines("updating graph with PR info"):
1243-
_update_graph_with_pr_info()
1315+
_update_graph_with_pr_info(package)
12441316
deploy(ctx, dirs_to_deploy=["version_pr_info", "pr_json", "pr_info"])
12451317

12461318
# record tmp dir so we can be sure to clean it later
@@ -1259,7 +1331,6 @@ def main(ctx: CliContext) -> None:
12591331
graph=gx,
12601332
smithy_version=smithy_version,
12611333
pinning_version=pinning_version,
1262-
dry_run=ctx.dry_run,
12631334
)
12641335
migrators = load_migrators()
12651336

@@ -1271,7 +1342,6 @@ def main(ctx: CliContext) -> None:
12711342
time_per_migrator,
12721343
tot_time_per_migrator,
12731344
) = _compute_time_per_migrator(
1274-
mctx,
12751345
migrators,
12761346
)
12771347
for i, migrator in enumerate(migrators):

conda_forge_tick/cli.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,20 @@ def update_upstream_versions(
149149

150150

151151
@main.command(name="auto-tick")
152+
@click.argument(
153+
"package",
154+
required=False,
155+
)
152156
@pass_context
153-
def auto_tick(ctx: CliContext) -> None:
157+
def auto_tick(ctx: CliContext, package: str | None) -> None:
158+
"""
159+
Run the main bot logic that runs all migrations, updates the graph accordingly, and opens the corresponding PRs.
160+
161+
If PACKAGE is given, only run the bot for that package, otherwise run the bot for all packages.
162+
"""
154163
from . import auto_tick
155164

156-
auto_tick.main(ctx)
165+
auto_tick.main(ctx, package=package)
157166

158167

159168
@main.command(name="make-status-report")

conda_forge_tick/contexts.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ class MigratorSessionContext:
3131
graph: DiGraph = None
3232
smithy_version: str = ""
3333
pinning_version: str = ""
34-
dry_run: bool = True
3534

3635

3736
@dataclass(frozen=True)

conda_forge_tick/lazy_json_backends.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,17 @@ def get_all_keys_for_hashmap(name):
630630
return backend.hkeys(name)
631631

632632

633+
def does_key_exist_in_hashmap(name: str, key: str) -> bool:
634+
"""
635+
Check if a key exists in a hashmap, using the primary backend.
636+
:param name: The hashmap name.
637+
:param key: The key to check.
638+
:return: True if the key exists, False otherwise.
639+
"""
640+
backend = LAZY_JSON_BACKENDS[CF_TICK_GRAPH_DATA_PRIMARY_BACKEND]()
641+
return backend.hexists(name, name)
642+
643+
633644
@contextlib.contextmanager
634645
def lazy_json_transaction():
635646
try:

conda_forge_tick/status_report.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,6 @@ def main() -> None:
398398
graph=gx,
399399
smithy_version=smithy_version,
400400
pinning_version=pinning_version,
401-
dry_run=False,
402401
)
403402
migrators = load_migrators()
404403

0 commit comments

Comments
 (0)