-
Notifications
You must be signed in to change notification settings - Fork 131
Description
The ado2gh rewire-pipeline command fails with HTTP 400 (Bad Request) on Classic (Designer) pipelines because the rewiring logic unconditionally sets settingsSourceType = 2 (YAML definitions) in the payload sent back to the ADO Build Definitions API. Classic pipelines use a Designer process (process.type = 1) and don't have YAML definitions, so the ADO API rejects the update with a 400.
Root Cause
In AdoPipelineTriggerService.cs line 232, the BuildPipelinePayload method hardcodes:
payload["settingsSourceType"] = 2;
settingsSourceType = 1means "pipeline settings are defined in the UI" (classic/designer pipelines) -process.type = 1settingsSourceType = 2means "pipeline settings come from a YAML file" (YAML pipelines) -process.type = 2
For classic pipelines, there is no YAML file - the build steps are stored as designer JSON inside ADO. Setting settingsSourceType = 2 tells ADO to look for a YAML file that doesn't exist, resulting in a 400 Bad Request.
Note: the loop above this line already copies the original settingsSourceType from the pipeline definition into the payload, but line 232 unconditionally overwrites it.
Reproduction
- Create a classic (designer) pipeline in Azure DevOps
- Run:
gh ado2gh rewire-pipeline --ado-org <org> --ado-team-project <project> --ado-pipeline <classic-pipeline-name> --github-org <org> --github-repo <repo> --service-connection-id <id> - Observe:
[WARNING] HTTP error retrieving pipeline <id> in <org>/<project>: Response status code does not indicate success: 400 (Bad Request).. Skipping pipeline rewiring.
YAML pipelines in the same project succeed.
Customer Impact
One customer has 38k pipelines, of which 14k are classic pipelines. All classic pipelines fail to rewire.
CLI version: v1.26.0 (also likely affects v1.27.0 since the code is unchanged).
Suggested Fix
- Preserve the original
settingsSourceTypefrom the pipeline definition instead of overriding it:
// Preserve original settingsSourceType (classic=1, YAML=2)
payload["settingsSourceType"] ??= 2;This keeps 1 for classic pipelines and defaults to 2 only if no value was present.
- The
process.typefield is already present in the pipeline definition response from_apis/build/definitions/{pipelineId}. The fix is to:
- Read
process.typefrom the fetched definition data - Set
settingsSourceType = 1(UI/Designer) for Classic pipelines andsettingsSourceType = 2(YAML) for YAML pipelines
Similarly, the RestorePipelineToAdoRepo method in AdoApi.cs hardcodes settingsSourceType = 1, which should also be reviewed.