Skip to content

Commit 1e92f2e

Browse files
committed
Add migration create options
1 parent 2e6b07c commit 1e92f2e

4 files changed

Lines changed: 93 additions & 1 deletion

File tree

azure-devops/azext_devops/dev/migration/_help.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ def load_migration_help():
3939
text: |
4040
az devops migrations create --org https://codedev.ms/elmo1 --repository-id 00000000-0000-0000-0000-000000000000 \
4141
--target-repository https://microsoft.ghe.com/1ES/Gardener --target-owner-user-id GeoffCoxMSFT --validate-only
42+
- name: Create a migration with optional validation settings.
43+
text: |
44+
az devops migrations create --org https://codedev.ms/elmo1 --repository-id 00000000-0000-0000-0000-000000000000 \
45+
--target-repository https://microsoft.ghe.com/1ES/Gardener --target-owner-user-id GeoffCoxMSFT \
46+
--agent-pool-name MigrationPool --skip-validation ActivePullRequestCount,PullRequestDeltaSize
4247
"""
4348

4449
helps['devops migrations pause'] = """

azure-devops/azext_devops/dev/migration/arguments.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ def load_migration_arguments(self, _):
2626
context.argument('scheduled_cutover_date', options_list='--scheduled-cutover-date',
2727
type=convert_date_string_to_iso8601,
2828
help='Scheduled cutover date/time (ISO 8601).')
29+
context.argument('agent_pool_name', options_list='--agent-pool-name',
30+
help='Agent pool name for migration validation.')
31+
context.argument('skip_validation', options_list='--skip-validation',
32+
help='Comma-separated list of validation checks to skip. '
33+
'Values: None, ActivePullRequestCount, PullRequestDeltaSize, '
34+
'TargetRepoMigration, All.')
2935

3036
with self.argument_context('devops migrations cutover set') as context:
3137
context.argument('scheduled_cutover_date', options_list='--scheduled-cutover-date',

azure-devops/azext_devops/dev/migration/migration.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ def list_migrations(organization=None, detect=None):
3030
return _send_request(client, 'GET', url)
3131

3232

33+
def _normalize_optional_text(value):
34+
if value is None:
35+
return None
36+
normalized = str(value).strip()
37+
return normalized if normalized else None
38+
39+
3340
def get_migration(repository_id=None, organization=None, detect=None):
3441
organization = _resolve_org_for_auth(organization, detect)
3542
repository_id = _resolve_repository_id(repository_id)
@@ -39,7 +46,10 @@ def get_migration(repository_id=None, organization=None, detect=None):
3946

4047

4148
def create_migration(repository_id=None, target_repository=None, target_owner_user_id=None,
42-
validate_only=None, scheduled_cutover_date=None, organization=None, detect=None):
49+
validate_only=None, scheduled_cutover_date=None, agent_pool_name=None,
50+
skip_validation=None, organization=None, detect=None):
51+
agent_pool_name = _normalize_optional_text(agent_pool_name)
52+
skip_validation = _normalize_optional_text(skip_validation)
4353
_validate_target_repository(target_repository)
4454
if not target_owner_user_id:
4555
raise CLIError('--target-owner-user-id must be specified.')
@@ -57,6 +67,10 @@ def create_migration(repository_id=None, target_repository=None, target_owner_us
5767
}
5868
if scheduled_cutover_date is not None:
5969
payload['scheduledCutoverDate'] = scheduled_cutover_date
70+
if agent_pool_name is not None:
71+
payload['agentPoolName'] = agent_pool_name
72+
if skip_validation is not None:
73+
payload['skipValidation'] = skip_validation
6074

6175
client = _get_service_client(organization)
6276
url = _build_migration_url(repository_id)

azure-devops/azext_devops/tests/latest/migration/test_migration.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,73 @@ def test_create_migration_payload_defaults_validate_only_true(self):
5656
payload = mock_send.call_args[0][3]
5757
self.assertTrue(payload['validateOnly'])
5858

59+
def test_create_migration_payload_includes_optional_fields(self):
60+
with patch('azext_devops.dev.migration.migration.resolve_instance') as mock_resolve, \
61+
patch('azext_devops.dev.migration.migration._get_service_client') as mock_client, \
62+
patch('azext_devops.dev.migration.migration._send_request') as mock_send:
63+
mock_send.return_value = {}
64+
mock_resolve.return_value = self._TEST_ORG
65+
66+
create_migration(
67+
repository_id='00000000-0000-0000-0000-000000000000',
68+
target_repository='https://microsoft.ghe.com/1ES/Gardener',
69+
target_owner_user_id='GeoffCoxMSFT',
70+
validate_only=False,
71+
scheduled_cutover_date='2030-12-31T11:59:00Z',
72+
agent_pool_name='MigrationPool',
73+
skip_validation='ActivePullRequestCount,PullRequestDeltaSize',
74+
organization=self._TEST_ORG,
75+
detect=False
76+
)
77+
78+
payload = mock_send.call_args[0][3]
79+
self.assertFalse(payload['validateOnly'])
80+
self.assertEqual(payload['scheduledCutoverDate'], '2030-12-31T11:59:00Z')
81+
self.assertEqual(payload['agentPoolName'], 'MigrationPool')
82+
self.assertEqual(payload['skipValidation'], 'ActivePullRequestCount,PullRequestDeltaSize')
83+
84+
def test_create_migration_omits_empty_optional_fields(self):
85+
with patch('azext_devops.dev.migration.migration.resolve_instance') as mock_resolve, \
86+
patch('azext_devops.dev.migration.migration._get_service_client') as mock_client, \
87+
patch('azext_devops.dev.migration.migration._send_request') as mock_send:
88+
mock_send.return_value = {}
89+
mock_resolve.return_value = self._TEST_ORG
90+
91+
create_migration(
92+
repository_id='00000000-0000-0000-0000-000000000000',
93+
target_repository='https://microsoft.ghe.com/1ES/Gardener',
94+
target_owner_user_id='GeoffCoxMSFT',
95+
agent_pool_name=' ',
96+
skip_validation=' ',
97+
organization=self._TEST_ORG,
98+
detect=False
99+
)
100+
101+
payload = mock_send.call_args[0][3]
102+
self.assertNotIn('agentPoolName', payload)
103+
self.assertNotIn('skipValidation', payload)
104+
105+
def test_create_migration_trims_optional_fields(self):
106+
with patch('azext_devops.dev.migration.migration.resolve_instance') as mock_resolve, \
107+
patch('azext_devops.dev.migration.migration._get_service_client') as mock_client, \
108+
patch('azext_devops.dev.migration.migration._send_request') as mock_send:
109+
mock_send.return_value = {}
110+
mock_resolve.return_value = self._TEST_ORG
111+
112+
create_migration(
113+
repository_id='00000000-0000-0000-0000-000000000000',
114+
target_repository='https://microsoft.ghe.com/1ES/Gardener',
115+
target_owner_user_id='GeoffCoxMSFT',
116+
agent_pool_name=' MigrationPool ',
117+
skip_validation=' ActivePullRequestCount, PullRequestDeltaSize ',
118+
organization=self._TEST_ORG,
119+
detect=False
120+
)
121+
122+
payload = mock_send.call_args[0][3]
123+
self.assertEqual(payload['agentPoolName'], 'MigrationPool')
124+
self.assertEqual(payload['skipValidation'], 'ActivePullRequestCount, PullRequestDeltaSize')
125+
59126
def test_create_migration_rejects_invalid_target_repository(self):
60127
with self.assertRaises(CLIError):
61128
create_migration(

0 commit comments

Comments
 (0)