Skip to content

Commit a6f174d

Browse files
authored
Merge pull request #52 from canvas-medical/db-20260204-stage-before-commit
Ensure files are staged before the changes are committed
2 parents 2866ae9 + cf23f91 commit a6f174d

File tree

2 files changed

+65
-24
lines changed

2 files changed

+65
-24
lines changed

canvas-plugin-assistant/scripts/git_commit_plugin.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ def run(cls, hook_info: HookInformation) -> None:
6262

6363
print(f"Wrap-up report found: {latest_report.name}", file=sys.stderr)
6464

65+
# Stage all files in the plugin directory
66+
cls._stage_files(plugin_dir)
67+
6568
# Check if there are any changes in the plugin directory
6669
if not cls._has_changes(plugin_dir):
6770
print("No changes detected in plugin directory, skipping commit", file=sys.stderr)
@@ -114,6 +117,35 @@ def _has_changes(cls, plugin_dir: Path) -> bool:
114117
finally:
115118
os.chdir(original_cwd)
116119

120+
@classmethod
121+
def _stage_files(cls, plugin_dir: Path) -> None:
122+
"""
123+
Stage all files in the plugin directory.
124+
125+
Uses `git add -A .` to stage all modified, added, and deleted files
126+
within the plugin directory.
127+
128+
Args:
129+
plugin_dir: Path to the plugin directory
130+
131+
Raises:
132+
subprocess.CalledProcessError: If the git command fails
133+
"""
134+
original_cwd = Path.cwd()
135+
try:
136+
os.chdir(plugin_dir)
137+
138+
# Stage all changes in plugin directory
139+
subprocess.run(
140+
["git", "add", "-A", "."],
141+
check=True,
142+
capture_output=True,
143+
text=True
144+
)
145+
146+
finally:
147+
os.chdir(original_cwd)
148+
117149
@classmethod
118150
def _commit_and_push(cls, plugin_dir: Path) -> None:
119151
"""

tests/canvas-plugin-assistant/scripts/test_git_commit_plugin.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,11 @@ def test_run__no_wrap_up_reports(self, mock_exit, tmp_path):
7777
exp_exit_calls = [call(0)]
7878
assert mock_exit.mock_calls == exp_exit_calls
7979

80+
@patch("git_commit_plugin.GitCommitPlugin._stage_files")
8081
@patch("git_commit_plugin.GitCommitPlugin._has_changes")
8182
@patch("git_commit_plugin.sys.exit")
8283
def test_run__no_changes_detected(
83-
self, mock_exit, mock_has_changes, tmp_path, capsys
84+
self, mock_exit, mock_has_changes, mock_stage_files, tmp_path, capsys
8485
):
8586
"""Test run exits 0 when _has_changes returns False."""
8687
hook_info = make_hook_info(tmp_path)
@@ -89,6 +90,7 @@ def test_run__no_changes_detected(
8990
artifacts_dir.mkdir()
9091
(artifacts_dir / "wrap-up-report-20240101.md").write_text("report content")
9192

93+
mock_stage_files.side_effect = [None]
9294
mock_has_changes.side_effect = [False]
9395
mock_exit.side_effect = [SystemExit(0)]
9496

@@ -97,8 +99,9 @@ def test_run__no_changes_detected(
9799
with pytest.raises(SystemExit):
98100
tested.run(hook_info)
99101

100-
exp_has_changes_calls = [call(hook_info.workspace_dir)]
101-
assert mock_has_changes.mock_calls == exp_has_changes_calls
102+
exp_calls = [call(hook_info.workspace_dir)]
103+
assert mock_stage_files.mock_calls == exp_calls
104+
assert mock_has_changes.mock_calls == exp_calls
102105

103106
# Verify print calls for wrap-up found and no changes detected
104107
captured = capsys.readouterr()
@@ -108,11 +111,12 @@ def test_run__no_changes_detected(
108111
exp_exit_calls = [call(0)]
109112
assert mock_exit.mock_calls == exp_exit_calls
110113

114+
@patch("git_commit_plugin.GitCommitPlugin._stage_files")
111115
@patch("git_commit_plugin.GitCommitPlugin._commit_and_push")
112116
@patch("git_commit_plugin.GitCommitPlugin._has_changes")
113117
@patch("git_commit_plugin.sys.exit")
114118
def test_run__success(
115-
self, mock_exit, mock_has_changes, mock_commit_and_push, tmp_path, capsys
119+
self, mock_exit, mock_has_changes, mock_commit_and_push, mock_stage_files, tmp_path, capsys
116120
):
117121
"""Test run exits 0 on successful commit and push."""
118122
hook_info = make_hook_info(tmp_path)
@@ -121,6 +125,7 @@ def test_run__success(
121125
artifacts_dir.mkdir()
122126
(artifacts_dir / "wrap-up-report-20240101.md").write_text("report content")
123127

128+
mock_stage_files.side_effect = [None]
124129
mock_has_changes.side_effect = [True]
125130
mock_commit_and_push.side_effect = [None]
126131
mock_exit.side_effect = [SystemExit(0)]
@@ -130,11 +135,10 @@ def test_run__success(
130135
with pytest.raises(SystemExit):
131136
tested.run(hook_info)
132137

133-
exp_has_changes_calls = [call(hook_info.workspace_dir)]
134-
assert mock_has_changes.mock_calls == exp_has_changes_calls
135-
136-
exp_commit_and_push_calls = [call(hook_info.workspace_dir)]
137-
assert mock_commit_and_push.mock_calls == exp_commit_and_push_calls
138+
exp_calls = [call(hook_info.workspace_dir)]
139+
assert mock_stage_files.mock_calls == exp_calls
140+
assert mock_has_changes.mock_calls == exp_calls
141+
assert mock_commit_and_push.mock_calls == exp_calls
138142

139143
# Verify print calls for wrap-up found and committing
140144
captured = capsys.readouterr()
@@ -144,11 +148,12 @@ def test_run__success(
144148
exp_exit_calls = [call(0)]
145149
assert mock_exit.mock_calls == exp_exit_calls
146150

151+
@patch("git_commit_plugin.GitCommitPlugin._stage_files")
147152
@patch("git_commit_plugin.GitCommitPlugin._commit_and_push")
148153
@patch("git_commit_plugin.GitCommitPlugin._has_changes")
149154
@patch("git_commit_plugin.sys.exit")
150155
def test_run__subprocess_error(
151-
self, mock_exit, mock_has_changes, mock_commit_and_push, tmp_path, capsys
156+
self, mock_exit, mock_has_changes, mock_commit_and_push, mock_stage_files, tmp_path, capsys
152157
):
153158
"""Test run exits 1 when subprocess.CalledProcessError is raised."""
154159
hook_info = make_hook_info(tmp_path)
@@ -157,6 +162,7 @@ def test_run__subprocess_error(
157162
artifacts_dir.mkdir()
158163
(artifacts_dir / "wrap-up-report-20240101.md").write_text("report content")
159164

165+
mock_stage_files.side_effect = [None]
160166
mock_has_changes.side_effect = [True]
161167
error = subprocess.CalledProcessError(1, "git push", stderr="push failed")
162168
mock_commit_and_push.side_effect = [error]
@@ -167,11 +173,10 @@ def test_run__subprocess_error(
167173
with pytest.raises(SystemExit):
168174
tested.run(hook_info)
169175

170-
exp_has_changes_calls = [call(hook_info.workspace_dir)]
171-
assert mock_has_changes.mock_calls == exp_has_changes_calls
172-
173-
exp_commit_and_push_calls = [call(hook_info.workspace_dir)]
174-
assert mock_commit_and_push.mock_calls == exp_commit_and_push_calls
176+
exp_calls = [call(hook_info.workspace_dir)]
177+
assert mock_stage_files.mock_calls == exp_calls
178+
assert mock_has_changes.mock_calls == exp_calls
179+
assert mock_commit_and_push.mock_calls == exp_calls
175180

176181
# Verify print was called with error message to stderr
177182
captured = capsys.readouterr()
@@ -182,11 +187,12 @@ def test_run__subprocess_error(
182187
exp_exit_calls = [call(1)]
183188
assert mock_exit.mock_calls == exp_exit_calls
184189

190+
@patch("git_commit_plugin.GitCommitPlugin._stage_files")
185191
@patch("git_commit_plugin.GitCommitPlugin._commit_and_push")
186192
@patch("git_commit_plugin.GitCommitPlugin._has_changes")
187193
@patch("git_commit_plugin.sys.exit")
188194
def test_run__generic_error(
189-
self, mock_exit, mock_has_changes, mock_commit_and_push, tmp_path, capsys
195+
self, mock_exit, mock_has_changes, mock_commit_and_push, mock_stage_files, tmp_path, capsys
190196
):
191197
"""Test run exits 1 when a generic Exception is raised."""
192198
hook_info = make_hook_info(tmp_path)
@@ -195,6 +201,7 @@ def test_run__generic_error(
195201
artifacts_dir.mkdir()
196202
(artifacts_dir / "wrap-up-report-20240101.md").write_text("report content")
197203

204+
mock_stage_files.side_effect = [None]
198205
mock_has_changes.side_effect = [True]
199206
mock_commit_and_push.side_effect = [Exception("Unexpected error occurred")]
200207
mock_exit.side_effect = [SystemExit(1)]
@@ -204,11 +211,10 @@ def test_run__generic_error(
204211
with pytest.raises(SystemExit):
205212
tested.run(hook_info)
206213

207-
exp_has_changes_calls = [call(hook_info.workspace_dir)]
208-
assert mock_has_changes.mock_calls == exp_has_changes_calls
209-
210-
exp_commit_and_push_calls = [call(hook_info.workspace_dir)]
211-
assert mock_commit_and_push.mock_calls == exp_commit_and_push_calls
214+
exp_calls = [call(hook_info.workspace_dir)]
215+
assert mock_stage_files.mock_calls == exp_calls
216+
assert mock_has_changes.mock_calls == exp_calls
217+
assert mock_commit_and_push.mock_calls == exp_calls
212218

213219
# Verify print was called with error message to stderr
214220
captured = capsys.readouterr()
@@ -219,10 +225,11 @@ def test_run__generic_error(
219225
exp_exit_calls = [call(1)]
220226
assert mock_exit.mock_calls == exp_exit_calls
221227

228+
@patch("git_commit_plugin.GitCommitPlugin._stage_files")
222229
@patch("git_commit_plugin.GitCommitPlugin._has_changes")
223230
@patch("git_commit_plugin.sys.exit")
224231
def test_run__multiple_reports_selects_most_recent(
225-
self, mock_exit, mock_has_changes, tmp_path, capsys
232+
self, mock_exit, mock_has_changes, mock_stage_files, tmp_path, capsys
226233
):
227234
"""Test run selects the most recent wrap-up report by mtime."""
228235
hook_info = make_hook_info(tmp_path)
@@ -238,6 +245,7 @@ def test_run__multiple_reports_selects_most_recent(
238245
report_newest = artifacts_dir / "wrap-up-report-newest.md"
239246
report_newest.write_text("newest report")
240247

248+
mock_stage_files.side_effect = [None]
241249
mock_has_changes.side_effect = [False]
242250
mock_exit.side_effect = [SystemExit(0)]
243251

@@ -246,8 +254,9 @@ def test_run__multiple_reports_selects_most_recent(
246254
with pytest.raises(SystemExit):
247255
tested.run(hook_info)
248256

249-
exp_has_changes_calls = [call(hook_info.workspace_dir)]
250-
assert mock_has_changes.mock_calls == exp_has_changes_calls
257+
exp_calls = [call(hook_info.workspace_dir)]
258+
assert mock_stage_files.mock_calls == exp_calls
259+
assert mock_has_changes.mock_calls == exp_calls
251260

252261
# Verify the print shows the most recent report
253262
captured = capsys.readouterr()

0 commit comments

Comments
 (0)