Skip to content

Commit 9ae4396

Browse files
bhuvanshahMSFTDemo User
andauthored
Remove legacy GitHub auth args from ELM migrations create (device flow only) (#1512)
* Remove service connection and GitHub token auth from ELM migrations create (device flow only) The server now supports third-party app auth (Git.EnterpriseLiveMigration.EnableThirdPartyAppAuth), so GitHub authentication for 'az devops migrations create' is handled entirely via interactive device flow. - Remove --service-endpoint-id and --github-token args (and ELM_GITHUB_TOKEN env var) - Device flow is now the only GitHub auth path; token is resolved from device flow and sent as gitHubUserToken - Update help text, examples, and unit tests accordingly * docs(elm): device-flow-only auth for migrations create Remove --github-token / ELM_GITHUB_TOKEN / --service-endpoint-id references from ELM docs; document interactive device flow as the sole GitHub auth path. * Remove preview labels from ELM migrations command groups and docs * Revert "Remove preview labels from ELM migrations command groups and docs" This reverts commit 74475fc. --------- Co-authored-by: Demo User <[email protected]>
1 parent ad7deee commit 9ae4396

6 files changed

Lines changed: 41 additions & 312 deletions

File tree

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,14 @@ def load_migration_help():
3838
helps['devops migrations create'] = """
3939
type: command
4040
short-summary: Create a migration for a repository.
41-
long-summary: 'If --github-token is not provided, the CLI checks ELM_GITHUB_TOKEN and then runs GitHub device flow to acquire a token.'
41+
long-summary: 'GitHub authentication uses device flow: the CLI prints a URL and a one-time code to complete sign-in interactively. No GitHub token or service connection is required.'
4242
examples:
4343
- name: Create a migration.
4444
text: |
4545
az devops migrations create --org https://dev.azure.com/myorg --repository-id 00000000-0000-0000-0000-000000000000 --target-repository https://github.com/OrgName/RepoName --agent-pool <your-agent-pool>
4646
- name: Create a validate-only migration.
4747
text: |
4848
az devops migrations create --org https://dev.azure.com/myorg --repository-id 00000000-0000-0000-0000-000000000000 --target-repository https://github.com/OrgName/RepoName --agent-pool <your-agent-pool> --validate-only --skip-validation ActivePullRequestCount,PullRequestDeltaSize
49-
- name: Create using a pre-generated GitHub token or PAT.
50-
text: |
51-
az devops migrations create --org https://dev.azure.com/myorg --repository-id 00000000-0000-0000-0000-000000000000 --target-repository https://github.com/OrgName/RepoName --github-token <token>
5249
"""
5350

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

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,6 @@ def load_migration_arguments(self, _):
6969
context.argument('target_owner_user_id', options_list='--target-owner-user-id',
7070
help='Target repository owner user ID. Deprecated and ignored when server-side '
7171
'token-based owner resolution is enabled.')
72-
context.argument('github_token', options_list='--github-token',
73-
help='GitHub user token used for user-identity verification on the target '
74-
'host. Independent of --service-endpoint-id. If omitted and '
75-
'--service-endpoint-id is not provided, the CLI checks ELM_GITHUB_TOKEN '
76-
'and then runs GitHub device flow. When --service-endpoint-id is '
77-
'provided, device flow is skipped; pass --github-token or set '
78-
'ELM_GITHUB_TOKEN to supply the user token.')
7972
context.argument('validate_only', options_list='--validate-only', action='store_true',
8073
help='Create in validate-only mode (pre-migration checks only).')
8174
context.argument('cutover_date', options_list='--cutover-date',
@@ -91,11 +84,6 @@ def load_migration_arguments(self, _):
9184
'MaxPullRequestSize, MaxPushPackSize, MaxReferenceNameLength, '
9285
'TargetRepositoryDoesNotExist, SourceRepositoryContainsLfsObjects, '
9386
'SourceRepositoryNotReadOnly, BoardsGitHubConnectionProvisioning, All.')
94-
context.argument('service_endpoint_id', options_list='--service-endpoint-id',
95-
help='Service endpoint ID (GUID) for the GitHub Enterprise Server connection '
96-
'used to sync commits to the target. Independent of user-identity '
97-
'verification: --github-token / ELM_GITHUB_TOKEN can be supplied '
98-
'alongside this flag. Device flow is skipped when this flag is set.')
9987
context.argument('enable_boards_github_connection',
10088
options_list=['--enable-boards-github-connection', '--enable-boards-gh'],
10189
action='store_true',

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

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
PIPELINES_API_PATH_SUFFIX = '/pipelines'
4040
DEVICE_FLOW_CONFIG_API_PATH = '/_apis/migrations/deviceFlowConfig'
4141
LEGACY_DEVICE_FLOW_CONFIG_API_PATH = '/_apis/elm/migrations/deviceFlowConfig'
42-
GITHUB_TOKEN_ENV_VAR = 'ELM_GITHUB_TOKEN'
4342
_SKIP_VALIDATION_POLICIES = {
4443
'none': 0,
4544
'activepullrequestcount': 1,
@@ -177,15 +176,13 @@ def get_migration(repository_id=None, organization=None, detect=None):
177176

178177
def create_migration(*, repository_id=None, target_repository=None, target_owner_user_id=None,
179178
validate_only=False, cutover_date=None, agent_pool=None,
180-
skip_validation=None, service_endpoint_id=None, github_token=None,
179+
skip_validation=None,
181180
enable_boards_github_connection=False, enable_auto_discover_pipelines=False,
182181
pipeline_service_connection_id=None,
183182
organization=None, detect=None):
184183
target_repository = _normalize_optional_text(target_repository)
185184
target_owner_user_id = _normalize_optional_text(target_owner_user_id)
186185
agent_pool = _normalize_optional_text(agent_pool)
187-
service_endpoint_id = _normalize_optional_text(service_endpoint_id)
188-
github_token = _normalize_optional_text(github_token)
189186
skip_validation = _parse_skip_validation(skip_validation)
190187

191188
if not target_repository:
@@ -202,14 +199,7 @@ def create_migration(*, repository_id=None, target_repository=None, target_owner
202199
organization = _resolve_org_for_auth(organization, detect)
203200
repository_id = _resolve_repository_id(repository_id)
204201
client = _get_service_client(organization)
205-
if not service_endpoint_id:
206-
github_token = _resolve_github_user_token(client, organization, target_repository, github_token)
207-
else:
208-
# SE supplies the GitHub credential used to sync commits. User-identity
209-
# verification (gitHubUserToken) is independent: accept an explicit
210-
# --github-token or ELM_GITHUB_TOKEN env var, but do not trigger device
211-
# flow here so non-interactive SE-based flows aren't broken.
212-
github_token = github_token or _normalize_optional_text(os.getenv(GITHUB_TOKEN_ENV_VAR))
202+
github_token = _resolve_github_user_token(client, organization, target_repository)
213203

214204
payload = {
215205
'targetRepository': target_repository,
@@ -225,8 +215,6 @@ def create_migration(*, repository_id=None, target_repository=None, target_owner
225215
payload['scheduledCutoverDate'] = cutover_date
226216
if skip_validation is not None:
227217
payload['skipValidation'] = skip_validation
228-
if service_endpoint_id:
229-
payload['serviceEndpointId'] = service_endpoint_id
230218
config_options = {}
231219
if enable_boards_github_connection:
232220
config_options['enableBoardsGitHubConnection'] = True
@@ -251,15 +239,7 @@ def create_migration(*, repository_id=None, target_repository=None, target_owner
251239
raise
252240

253241

254-
def _resolve_github_user_token(client, organization, target_repository, github_token=None):
255-
token = _normalize_optional_text(github_token)
256-
if token:
257-
return token
258-
259-
env_token = _normalize_optional_text(os.getenv(GITHUB_TOKEN_ENV_VAR))
260-
if env_token:
261-
return env_token
262-
242+
def _resolve_github_user_token(client, organization, target_repository):
263243
flow_config = _get_device_flow_config(client, organization, target_repository)
264244
client_id = _normalize_optional_text(flow_config.get('clientId'))
265245
enterprise_url = _normalize_optional_text(flow_config.get('enterpriseUrl'))
@@ -285,7 +265,8 @@ def _get_device_flow_config(client, organization, target_repository):
285265
continue
286266
if index == 1 and first_error and 'status 404' in str(ex):
287267
raise CLIError('GitHub device-flow configuration is unavailable. '
288-
'Provide --github-token or set ELM_GITHUB_TOKEN to continue.')
268+
'Ensure the GitHub app is installed for the target '
269+
'organization, then try again.')
289270
raise
290271

291272
if first_error:
@@ -394,7 +375,7 @@ def _post_form(url, data):
394375
if ex.code in (401, 403):
395376
raise CLIError('GitHub device flow is unavailable for this organization. '
396377
'This can happen if the GitHub app is not installed or the service is unavailable. '
397-
'Try again later, or provide --github-token (or set ELM_GITHUB_TOKEN).')
378+
'Try again later.')
398379
detail = ''
399380
try:
400381
content = ex.read()

0 commit comments

Comments
 (0)