Skip to content

Commit b1df02b

Browse files
Add linters and formatters to CI when pre-commit isn't used (#249)
* Add linters and formatters to CI when pre-commit isn't used * Fix tool add order
1 parent cdb9b68 commit b1df02b

File tree

8 files changed

+487
-100
lines changed

8 files changed

+487
-100
lines changed

src/usethis/_ci.py

+45-13
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
from usethis._integrations.bitbucket.anchor import ScriptItemAnchor
55
from usethis._integrations.bitbucket.schema import Script, Step
66
from usethis._integrations.bitbucket.steps import (
7-
add_step_in_default,
7+
add_bitbucket_step_in_default,
88
get_steps_in_default,
9-
remove_step_from_default,
9+
remove_bitbucket_step_from_default,
1010
)
1111
from usethis._integrations.uv.python import get_supported_major_python_versions
1212

@@ -15,22 +15,54 @@ def is_bitbucket_used() -> bool:
1515
return (Path.cwd() / "bitbucket-pipelines.yml").exists()
1616

1717

18-
def add_bitbucket_pre_commit_step() -> None:
19-
add_step_in_default(_get_bitbucket_pre_commit_step())
18+
def get_bitbucket_pre_commit_step() -> Step:
19+
return Step(
20+
name="Run pre-commit",
21+
caches=["uv", "pre-commit"],
22+
script=Script(
23+
[
24+
ScriptItemAnchor(name="install-uv"),
25+
"uv run pre-commit run --all-files",
26+
]
27+
),
28+
)
2029

2130

22-
def remove_bitbucket_pre_commit_step() -> None:
23-
remove_step_from_default(_get_bitbucket_pre_commit_step())
31+
def get_bitbucket_ruff_step() -> Step:
32+
return Step(
33+
name="Run Ruff",
34+
caches=["uv"],
35+
script=Script(
36+
[
37+
ScriptItemAnchor(name="install-uv"),
38+
"uv run ruff check --fix",
39+
"uv run ruff format",
40+
]
41+
),
42+
)
2443

2544

26-
def _get_bitbucket_pre_commit_step() -> Step:
45+
def get_bitbucket_deptry_step() -> Step:
2746
return Step(
28-
name="Run pre-commit",
29-
caches=["uv", "pre-commit"],
47+
name="Run Deptry",
48+
caches=["uv"],
3049
script=Script(
3150
[
3251
ScriptItemAnchor(name="install-uv"),
33-
"uv run pre-commit run --all-files",
52+
"uv run deptry src",
53+
]
54+
),
55+
)
56+
57+
58+
def get_bitbucket_pyproject_fmt_step() -> Step:
59+
return Step(
60+
name="Run pyproject-fmt",
61+
caches=["uv"],
62+
script=Script(
63+
[
64+
ScriptItemAnchor(name="install-uv"),
65+
"uv run pyproject-fmt pyproject.toml",
3466
]
3567
),
3668
)
@@ -39,7 +71,7 @@ def _get_bitbucket_pre_commit_step() -> Step:
3971
def update_bitbucket_pytest_steps() -> None:
4072
matrix = get_supported_major_python_versions()
4173
for version in matrix:
42-
add_step_in_default(
74+
add_bitbucket_step_in_default(
4375
Step(
4476
name=f"Test on 3.{version}",
4577
caches=["uv"],
@@ -58,11 +90,11 @@ def update_bitbucket_pytest_steps() -> None:
5890
if match:
5991
version = int(match.group(1))
6092
if version not in matrix:
61-
remove_step_from_default(step)
93+
remove_bitbucket_step_from_default(step)
6294

6395

6496
def remove_bitbucket_pytest_steps() -> None:
6597
# Remove any with pattern "^Test on 3.\d+$"
6698
for step in get_steps_in_default():
6799
if step.name is not None and re.match(r"^Test on 3.\d+$", step.name):
68-
remove_step_from_default(step)
100+
remove_bitbucket_step_from_default(step)

src/usethis/_core/ci.py

+28-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
from usethis._ci import (
2-
add_bitbucket_pre_commit_step,
2+
get_bitbucket_deptry_step,
3+
get_bitbucket_pre_commit_step,
4+
get_bitbucket_pyproject_fmt_step,
5+
get_bitbucket_ruff_step,
36
update_bitbucket_pytest_steps,
47
)
58
from usethis._console import box_print, info_print
69
from usethis._integrations.bitbucket.config import (
710
add_bitbucket_pipeline_config,
811
remove_bitbucket_pipeline_config,
912
)
13+
from usethis._integrations.bitbucket.steps import add_bitbucket_step_in_default
1014
from usethis._integrations.uv.init import ensure_pyproject_toml
11-
from usethis._tool import PreCommitTool, PytestTool
15+
from usethis._tool import (
16+
DeptryTool,
17+
PreCommitTool,
18+
PyprojectFmtTool,
19+
PytestTool,
20+
RuffTool,
21+
)
1222

1323

1424
def use_ci_bitbucket(*, remove: bool = False) -> None:
@@ -17,12 +27,26 @@ def use_ci_bitbucket(*, remove: bool = False) -> None:
1727
if not remove:
1828
use_pre_commit = PreCommitTool().is_used()
1929
use_pytest = PytestTool().is_used()
20-
use_any_tool = use_pre_commit or use_pytest
30+
use_ruff = RuffTool().is_used()
31+
use_deptry = DeptryTool().is_used()
32+
use_pyproject_fmt = PyprojectFmtTool().is_used()
33+
use_any_tool = (
34+
use_pre_commit or use_pytest or use_ruff or use_deptry or use_pyproject_fmt
35+
)
2136

2237
add_bitbucket_pipeline_config(report_placeholder=not use_any_tool)
2338

2439
if use_pre_commit:
25-
add_bitbucket_pre_commit_step()
40+
add_bitbucket_step_in_default(get_bitbucket_pre_commit_step())
41+
else:
42+
# This order should match the canonical order in the function which add
43+
# steps
44+
if use_pyproject_fmt:
45+
add_bitbucket_step_in_default(get_bitbucket_pyproject_fmt_step())
46+
if use_ruff:
47+
add_bitbucket_step_in_default(get_bitbucket_ruff_step())
48+
if use_deptry:
49+
add_bitbucket_step_in_default(get_bitbucket_deptry_step())
2650

2751
if use_pytest:
2852
update_bitbucket_pytest_steps()

src/usethis/_core/tool.py

+46-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
from pathlib import Path
22

33
from usethis._ci import (
4-
add_bitbucket_pre_commit_step,
4+
get_bitbucket_deptry_step,
5+
get_bitbucket_pre_commit_step,
6+
get_bitbucket_pyproject_fmt_step,
7+
get_bitbucket_ruff_step,
58
is_bitbucket_used,
6-
remove_bitbucket_pre_commit_step,
79
remove_bitbucket_pytest_steps,
810
update_bitbucket_pytest_steps,
911
)
1012
from usethis._console import box_print, tick_print
13+
from usethis._integrations.bitbucket.steps import (
14+
add_bitbucket_step_in_default,
15+
remove_bitbucket_step_from_default,
16+
)
1117
from usethis._integrations.pre_commit.core import (
1218
install_pre_commit_hooks,
1319
remove_pre_commit_config,
@@ -78,11 +84,14 @@ def use_deptry(*, remove: bool = False) -> None:
7884
add_deps_to_group(tool.dev_deps, "dev")
7985
if PreCommitTool().is_used():
8086
tool.add_pre_commit_repo_configs()
87+
elif is_bitbucket_used():
88+
add_bitbucket_step_in_default(get_bitbucket_deptry_step())
8189

8290
box_print("Run 'deptry src' to run deptry.")
8391
else:
84-
if PreCommitTool().is_used():
85-
tool.remove_pre_commit_repo_configs()
92+
tool.remove_pre_commit_repo_configs()
93+
remove_bitbucket_step_from_default(get_bitbucket_deptry_step())
94+
8695
remove_deps_from_group(tool.dev_deps, "dev")
8796

8897

@@ -113,12 +122,14 @@ def use_pre_commit(*, remove: bool = False) -> None:
113122
install_pre_commit_hooks()
114123

115124
if is_bitbucket_used():
116-
add_bitbucket_pre_commit_step()
125+
add_bitbucket_step_in_default(get_bitbucket_pre_commit_step())
126+
_remove_bitbucket_linter_steps_from_default()
117127

118128
box_print("Run 'pre-commit run --all-files' to run the hooks manually.")
119129
else:
120130
if is_bitbucket_used():
121-
remove_bitbucket_pre_commit_step()
131+
remove_bitbucket_step_from_default(get_bitbucket_pre_commit_step())
132+
_add_bitbucket_linter_steps_to_default()
122133

123134
# Need pre-commit to be installed so we can uninstall hooks
124135
add_deps_to_group(tool.dev_deps, "dev")
@@ -139,6 +150,26 @@ def use_pre_commit(*, remove: bool = False) -> None:
139150
_requirements_txt_instructions_basic()
140151

141152

153+
def _add_bitbucket_linter_steps_to_default() -> None:
154+
# This order of adding tools should be synced with the order hard-coded
155+
# in the function which adds steps.
156+
if is_bitbucket_used():
157+
if PyprojectFmtTool().is_used():
158+
add_bitbucket_step_in_default(get_bitbucket_pyproject_fmt_step())
159+
if DeptryTool().is_used():
160+
add_bitbucket_step_in_default(get_bitbucket_deptry_step())
161+
if RuffTool().is_used():
162+
add_bitbucket_step_in_default(get_bitbucket_ruff_step())
163+
164+
165+
def _remove_bitbucket_linter_steps_from_default() -> None:
166+
# This order of removing tools should be synced with the order hard-coded
167+
# in the function which adds steps.
168+
remove_bitbucket_step_from_default(get_bitbucket_pyproject_fmt_step())
169+
remove_bitbucket_step_from_default(get_bitbucket_deptry_step())
170+
remove_bitbucket_step_from_default(get_bitbucket_ruff_step())
171+
172+
142173
def use_pyproject_fmt(*, remove: bool = False) -> None:
143174
tool = PyprojectFmtTool()
144175

@@ -149,6 +180,8 @@ def use_pyproject_fmt(*, remove: bool = False) -> None:
149180

150181
if not is_pre_commit:
151182
add_deps_to_group(tool.dev_deps, "dev")
183+
if is_bitbucket_used():
184+
add_bitbucket_step_in_default(get_bitbucket_pyproject_fmt_step())
152185
else:
153186
tool.add_pre_commit_repo_configs()
154187

@@ -159,9 +192,9 @@ def use_pyproject_fmt(*, remove: bool = False) -> None:
159192
else:
160193
_pyproject_fmt_instructions_pre_commit()
161194
else:
195+
remove_bitbucket_step_from_default(get_bitbucket_pyproject_fmt_step())
162196
tool.remove_pyproject_configs()
163-
if PreCommitTool().is_used():
164-
tool.remove_pre_commit_repo_configs()
197+
tool.remove_pre_commit_repo_configs()
165198
remove_deps_from_group(tool.dev_deps, "dev")
166199

167200

@@ -252,8 +285,7 @@ def use_requirements_txt(*, remove: bool = False) -> None:
252285
else:
253286
_requirements_txt_instructions_pre_commit()
254287
else:
255-
if PreCommitTool().is_used():
256-
tool.remove_pre_commit_repo_configs()
288+
tool.remove_pre_commit_repo_configs()
257289

258290
if path.exists() and path.is_file():
259291
tick_print("Removing 'requirements.txt'.")
@@ -306,11 +338,13 @@ def use_ruff(*, remove: bool = False) -> None:
306338
ignore_ruff_rules(ignored_rules)
307339
if PreCommitTool().is_used():
308340
tool.add_pre_commit_repo_configs()
341+
elif is_bitbucket_used():
342+
add_bitbucket_step_in_default(get_bitbucket_ruff_step())
309343

310344
box_print("Run 'ruff check --fix' to run the Ruff linter with autofixes.")
311345
box_print("Run 'ruff format' to run the Ruff formatter.")
312346
else:
313-
if PreCommitTool().is_used():
314-
tool.remove_pre_commit_repo_configs()
347+
tool.remove_pre_commit_repo_configs()
348+
remove_bitbucket_step_from_default(get_bitbucket_ruff_step())
315349
tool.remove_pyproject_configs() # N.B. this will remove the selected Ruff rules
316350
remove_deps_from_group(tool.dev_deps, "dev")

src/usethis/_integrations/bitbucket/steps.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
script_item.yaml_set_anchor(value=name, always_dump=True)
6060

6161

62-
def add_step_in_default(step: Step) -> None:
62+
def add_bitbucket_step_in_default(step: Step) -> None:
6363
try:
6464
existing_steps = get_steps_in_default()
6565
except UnexpectedImportPipelineError:
@@ -88,7 +88,7 @@ def add_step_in_default(step: Step) -> None:
8888
placeholder = _get_placeholder_step()
8989
if not _steps_are_equivalent(placeholder, step):
9090
# Only remove the placeholder if it hasn't already been added.
91-
remove_step_from_default(placeholder)
91+
remove_bitbucket_step_from_default(placeholder)
9292

9393

9494
def _add_step_in_default_via_doc(
@@ -154,9 +154,12 @@ def _add_step_in_default_via_doc(
154154
# See https://github.com/nathanjmcdougall/usethis-python/issues/149
155155
step_order = [
156156
"Run pre-commit",
157+
# For these tools, sync them with the pre-commit removal logic
158+
"Run pyproject-fmt",
159+
"Run Ruff",
160+
"Run Deptry",
157161
*[f"Test on 3.{maj}" for maj in get_supported_major_python_versions()],
158162
]
159-
160163
for step_name in step_order:
161164
if step_name == step.name:
162165
break
@@ -173,7 +176,7 @@ def _add_step_in_default_via_doc(
173176
)
174177

175178

176-
def remove_step_from_default(step: Step) -> None:
179+
def remove_bitbucket_step_from_default(step: Step) -> None:
177180
"""Remove a step from the default pipeline in the Bitbucket Pipelines configuration.
178181
179182
If the default pipeline does not exist, or the step is not found, nothing happens.
@@ -402,7 +405,7 @@ def _(item: StageItem) -> list[Step]:
402405

403406

404407
def add_placeholder_step_in_default(report_placeholder: bool = True) -> None:
405-
add_step_in_default(_get_placeholder_step())
408+
add_bitbucket_step_in_default(_get_placeholder_step())
406409

407410
if report_placeholder:
408411
tick_print(

0 commit comments

Comments
 (0)