Skip to content

Commit e448b52

Browse files
Allow sync function to continue syncing repositories despite migration errors (#82)
Co-authored-by: Kevin Grandjean <[email protected]>
1 parent 64c75f6 commit e448b52

File tree

2 files changed

+157
-6
lines changed

2 files changed

+157
-6
lines changed

gitea_github_sync/cli.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ def migrate_repo(full_repo_name: str) -> None:
6060
print(f"[b red]Repository {full_repo_name} does not exist on Github[/]")
6161
raise click.Abort()
6262

63-
gt.migrate_repo(repo=repo, github_token=conf.github_token)
63+
try:
64+
gt.migrate_repo(repo=repo, github_token=conf.github_token)
65+
except gitea.GiteaMigrationError as e:
66+
print(f"[red]Migration Error for [b]{e.full_repo_name}[/]")
6467

6568

6669
@cli.command()
@@ -73,8 +76,18 @@ def sync() -> None:
7376
repos_to_sync = migration.list_missing_github_repos(
7477
gh_repos=github_repos, gitea_repos=gitea_repos
7578
)
76-
print(f"Starting migration for {len(repos_to_sync)} repos")
79+
len_repos = len(repos_to_sync)
80+
print(f"Starting migration for {len_repos} repos")
7781
for repo in repos_to_sync:
7882
print(f"Migrating [b]{repo.full_repo_name}[/]")
79-
gt.migrate_repo(repo=repo, github_token=conf.github_token)
80-
print(f"Migrated {len(repos_to_sync)} repos successfully")
83+
try:
84+
gt.migrate_repo(repo=repo, github_token=conf.github_token)
85+
except gitea.GiteaMigrationError as e:
86+
print(f"[red]Migration Error for [b]{e.full_repo_name}[/]")
87+
len_repos -= 1
88+
if len_repos == 0:
89+
print("No repos were migrated")
90+
else:
91+
print(f"Migrated {len_repos} out of {len(repos_to_sync)} repos successfully")
92+
if len_repos < len(repos_to_sync):
93+
print(f"Failed {len(repos_to_sync) - len_repos} out of {len(repos_to_sync)} migrations")

tests/test_cli.py

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from click.testing import CliRunner
88

99
from gitea_github_sync.cli import cli, print_repositories
10+
from gitea_github_sync.gitea import GiteaMigrationError
1011
from gitea_github_sync.repository import Repository, Visibility
1112

1213

@@ -127,6 +128,40 @@ def test_migrate_repo_no_match(
127128
mock_load_config.assert_called_once()
128129

129130

131+
@patch("gitea_github_sync.cli.config.load_config", autospec=True)
132+
@patch("gitea_github_sync.cli.github.list_all_repositories", autospec=True)
133+
@patch("gitea_github_sync.cli.github.get_github", autospec=True)
134+
@patch("gitea_github_sync.cli.gitea.get_gitea", autospec=True)
135+
def test_migrate_repo_gitea_migration_error(
136+
mock_get_gitea: MagicMock,
137+
mock_get_github: MagicMock,
138+
mock_list_all_repositories: MagicMock,
139+
mock_load_config: MagicMock,
140+
repositories_fixture: List[Repository],
141+
) -> None:
142+
expected_repo = Repository("Muscaw/gitea-github-sync", Visibility.PRIVATE)
143+
expected_github_token = "some-github-token"
144+
145+
type(mock_load_config.return_value).github_token = PropertyMock(
146+
return_value=expected_github_token
147+
)
148+
mock_list_all_repositories.return_value = repositories_fixture + [expected_repo]
149+
mock_get_gitea.return_value.migrate_repo.side_effect = GiteaMigrationError(
150+
full_repo_name=expected_repo.full_repo_name
151+
)
152+
153+
runner = CliRunner()
154+
command = ["migrate-repo", "Muscaw/gitea-github-sync"]
155+
result = runner.invoke(cli, command)
156+
157+
assert result.exit_code == 0
158+
assert "Migration Error for Muscaw/gitea-github-sync" in result.stdout
159+
mock_list_all_repositories.assert_called_once_with(mock_get_github.return_value)
160+
mock_get_gitea.return_value.migrate_repo.assert_called_once_with(
161+
repo=expected_repo, github_token=expected_github_token
162+
)
163+
164+
130165
NO_REPOS: List[Repository] = []
131166
MULTIPLE_REPOS = [
132167
Repository("some-team/a-repo", Visibility.PUBLIC),
@@ -143,7 +178,7 @@ def test_migrate_repo_no_match(
143178
textwrap.dedent(
144179
"""\
145180
Starting migration for 0 repos
146-
Migrated 0 repos successfully
181+
No repos were migrated
147182
"""
148183
),
149184
),
@@ -155,7 +190,7 @@ def test_migrate_repo_no_match(
155190
Migrating some-team/a-repo
156191
Migrating some-team/b-repo
157192
Migrating some-team/c-repo
158-
Migrated 3 repos successfully
193+
Migrated 3 out of 3 repos successfully
159194
"""
160195
),
161196
),
@@ -199,6 +234,109 @@ def test_sync(
199234
)
200235

201236

237+
REPOS_MIGRATION_ERR = [
238+
Repository("some-team/a-repo", Visibility.PUBLIC),
239+
Repository("some-team/migerr-repo", Visibility.PRIVATE),
240+
Repository("some-team/c-repo", Visibility.UNKNOWN),
241+
]
242+
243+
244+
@pytest.mark.parametrize(
245+
"repos_to_sync, expected_output",
246+
[
247+
(
248+
NO_REPOS,
249+
textwrap.dedent(
250+
"""\
251+
Starting migration for 0 repos
252+
No repos were migrated
253+
"""
254+
),
255+
),
256+
(
257+
MULTIPLE_REPOS,
258+
textwrap.dedent(
259+
"""\
260+
Starting migration for 3 repos
261+
Migrating some-team/a-repo
262+
Migrating some-team/b-repo
263+
Migrating some-team/c-repo
264+
Migrated 3 out of 3 repos successfully
265+
"""
266+
),
267+
),
268+
(
269+
[Repository("some-team/a-repo", Visibility.PUBLIC)],
270+
textwrap.dedent(
271+
"""\
272+
Starting migration for 1 repos
273+
Migrating some-team/a-repo
274+
Migrated 1 out of 1 repos successfully
275+
"""
276+
),
277+
),
278+
(
279+
REPOS_MIGRATION_ERR,
280+
textwrap.dedent(
281+
"""\
282+
Starting migration for 3 repos
283+
Migrating some-team/a-repo
284+
Migrating some-team/migerr-repo
285+
Migration Error for some-team/migerr-repo
286+
Migrating some-team/c-repo
287+
Migrated 2 out of 3 repos successfully
288+
Failed 1 out of 3 migrations
289+
"""
290+
),
291+
),
292+
],
293+
)
294+
@patch("gitea_github_sync.cli.migration.list_missing_github_repos", autospec=True)
295+
@patch("gitea_github_sync.cli.config.load_config", autospec=True)
296+
@patch("gitea_github_sync.cli.github.list_all_repositories", autospec=True)
297+
@patch("gitea_github_sync.cli.github.get_github", autospec=True)
298+
@patch("gitea_github_sync.cli.gitea.get_gitea", autospec=True)
299+
def test_sync_with_errors(
300+
mock_get_gitea: MagicMock,
301+
mock_get_github: MagicMock,
302+
mock_list_all_repositories: MagicMock,
303+
mock_load_config: MagicMock,
304+
mock_list_missing_github_repos: MagicMock,
305+
repos_to_sync: List[Repository],
306+
expected_output: str,
307+
) -> None:
308+
expected_github_token = "some-github-token"
309+
310+
type(mock_load_config.return_value).github_token = PropertyMock(
311+
return_value=expected_github_token
312+
)
313+
mock_list_missing_github_repos.return_value = repos_to_sync
314+
mock_get_gitea.return_value.get_repos.return_value = MULTIPLE_REPOS
315+
316+
# Mocking migrate_repo to raise an error for 'some-team/migerr-repo'
317+
def migrate_repo_side_effect(repo: Repository, github_token: str) -> None:
318+
if repo.full_repo_name == "some-team/migerr-repo":
319+
raise GiteaMigrationError(full_repo_name=repo.full_repo_name)
320+
321+
mock_get_gitea.return_value.migrate_repo.side_effect = migrate_repo_side_effect
322+
323+
runner = CliRunner()
324+
command = ["sync"]
325+
result = runner.invoke(cli, command)
326+
327+
assert result.exit_code == 0
328+
assert result.stdout == expected_output
329+
mock_load_config.assert_called_once()
330+
mock_list_all_repositories.assert_called_once_with(mock_get_github.return_value)
331+
mock_list_missing_github_repos.assert_called_once_with(
332+
gh_repos=mock_list_all_repositories.return_value,
333+
gitea_repos=mock_get_gitea.return_value.get_repos.return_value,
334+
)
335+
mock_get_gitea.return_value.migrate_repo.assert_has_calls(
336+
[call(repo=repo, github_token=expected_github_token) for repo in repos_to_sync]
337+
)
338+
339+
202340
@patch("sys.stdout", new_callable=StringIO)
203341
def test_print_repositories_without_stats(
204342
stdout: StringIO,

0 commit comments

Comments
 (0)