# How no-mistakes Creates Pull Requests in Azure DevOps: CLI Integration Deep Dive

> Learn how no-mistakes seamlessly creates pull requests in Azure DevOps using CLI integration. Discover the simple setup and automatic parameter extraction for efficient PR management.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: deep-dive
- Published: 2026-07-03

---

**no-mistakes integrates with Azure DevOps by wrapping the official `az` CLI extension, detecting the provider from repository URLs, and executing `az repos pr create` commands with automatically extracted organization, project, and repository parameters.**

The `kunchenguid/no-mistakes` repository automates pull request workflows across multiple SCM providers. For Azure DevOps specifically, it implements a lightweight Go wrapper around the Azure CLI rather than using REST APIs directly, enabling seamless **no-mistakes Azure DevOps PR integration** while maintaining consistent interfaces with GitHub, GitLab, and Bitbucket hosts.

## Provider Detection and Host Initialization

### Detecting Azure DevOps Repositories

Before creating PRs, no-mistakes identifies Azure DevOps repositories by analyzing the upstream URL. The `scm.DetectProvider` function in [`internal/scm/scm.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/scm.go) recognizes Azure DevOps URLs through substring matching for `dev.azure.com` or `visualstudio.com` domains (lines 24-33).

When the pipeline reaches the PR step, this detection triggers the construction of an Azure DevOps-specific host implementation.

### Building the Azure DevOps Host

The `buildHost` function in [`internal/pipeline/steps/host.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/host.go) (lines 66-83) constructs the Azure DevOps host by parsing the remote URL and initializing the wrapper:

```go
return azuredevops.New(
    cmdFactory,
    func() bool { return stepCLIAvailable(sctx, provider) },
    org, project, repo), ""

```

The `azuredevops.New` constructor in [`internal/scm/azuredevops/azuredevops.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/azuredevops/azuredevops.go) (lines 45-67) stores three critical components: the command factory, a CLI availability checker, and the extracted org/project/repo identifiers required for all `az` commands.

## Creating Pull Requests via the Azure CLI

### Command Construction and Execution

The `CreatePR` method in [`internal/scm/azuredevops/azuredevops.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/azuredevops/azuredevops.go) (lines 90-100) builds the CLI command dynamically:

```go
args := []string{
    "repos", "pr", "create",
    "--source-branch", branch,
    "--target-branch", base,
    "--title", content.Title,
    "--description", clampDescription(content.Body),
}
args = append(args, h.scopeArgs()...)
args = append(args, "--output", "json")
out, err := outputJSON(h.cmd(ctx, "az", args...))

```

The `scopeArgs` method appends the required `--organization`, `--project`, and `--repository` flags derived from URL parsing. The command returns JSON output, which unmarshals into an `azPR` struct and converts to the generic `scm.PR` type containing the PR number and browsable URL (lines 59-80).

### Handling PR Metadata and Limits

Azure DevOps enforces description length limitations that could truncate PR bodies. The `clampDescription` function (lines 34-40) enforces the `scm.MaxPRBodyChars` limit before submission, ensuring the CLI command succeeds without validation errors.

## PR Lifecycle Management

### Finding and Updating Existing PRs

Beyond creation, no-mistakes manages PR states through additional CLI wrappers:

- **`FindPR`**: Lists active PRs for a specific branch using `az repos pr list`
- **`UpdatePR`**: Modifies existing PRs via `az repos pr update` with `--title` and `--description` flags

These operations use the same scope arguments and JSON parsing patterns as the creation flow.

### Status Checks and Mergeability

The host implements polling capabilities for CI/CD integration:

- **`GetPRState`**: Retrieves current PR status via `az repos pr show`
- **`GetMergeableState`**: Determines merge readiness
- **`GetChecks`**: Fetches policy evaluation results using `az repos pr policy list`

These methods enable the pipeline to block or proceed based on Azure DevOps branch policies and build validation status.

## CLI Availability and Authentication

The `Available` method in [`internal/scm/azuredevops/azuredevops.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/azuredevops/azuredevops.go) (lines 103-119) validates that the `az` CLI is installed, the Azure DevOps extension is present, and the user is authenticated. This early validation surfaces configuration errors before attempting PR creation, preventing cryptic failures mid-pipeline.

## Implementation Example

The following Go code demonstrates the integration flow as implemented in [`internal/pipeline/steps/pr.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/pr.go) (lines 101-108):

```go
// Detect provider from repository URL
provider := scm.DetectProvider(sctx.Repo.UpstreamURL) // → ProviderAzureDevOps

// Build the appropriate host
host, _ := steps.BuildHost(sctx, provider) // returns *azuredevops.Host

// Prepare PR content
prContent := scm.PRContent{
    Title: "feat: add Azure DevOps PR integration",
    Body:  "## What Changed\n- Implemented Azure DevOps host\n- Added PR creation flow",

}

// Create the pull request
created, err := host.CreatePR(context.Background(), "feature/azure-devops", "main", prContent)
if err != nil {
    log.Fatalf("PR creation failed: %v", err)
}
fmt.Printf("Created PR: %s\n", created.URL)

```

## Summary

- **no-mistakes** detects Azure DevOps repositories by scanning for `dev.azure.com` or `visualstudio.com` in remote URLs via `scm.DetectProvider`.
- The Azure DevOps host in [`internal/scm/azuredevops/azuredevops.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/azuredevops/azuredevops.go) wraps the `az` CLI extension rather than using REST APIs.
- PR creation executes `az repos pr create` with automatically scoped `--organization`, `--project`, and `--repository` arguments.
- Description lengths are clamped to Azure DevOps limits using `clampDescription` before submission.
- The integration supports full PR lifecycle management including updates, status checks, and mergeability polling through consistent CLI commands.

## Frequently Asked Questions

### How does no-mistakes detect Azure DevOps repositories?

The `DetectProvider` function in [`internal/scm/scm.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/scm.go) (lines 24-33) inspects the repository upstream URL for `dev.azure.com` or `visualstudio.com` substrings. When matched, it returns `ProviderAzureDevOps`, triggering the Azure-specific host construction in the pipeline step.

### What Azure CLI commands does no-mistakes use for PR creation?

According to the source code in [`internal/scm/azuredevops/azuredevops.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/azuredevops/azuredevops.go), no-mistakes executes `az repos pr create` with flags for source/target branches, title, description, and scope parameters. It also uses `az repos pr list` for discovery, `az repos pr update` for modifications, and `az repos pr policy list` for status checks.

### How does no-mistakes handle Azure DevOps description length limits?

The `clampDescription` function (lines 34-40) truncates PR descriptions to the maximum character limit defined by `scm.MaxPRBodyChars` before passing them to the CLI. This prevents Azure DevOps from rejecting PRs with excessively long bodies.

### Can no-mistakes update existing PRs in Azure DevOps?

Yes. The `UpdatePR` method in [`internal/scm/azuredevops/azuredevops.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/scm/azuredevops/azuredevops.go) executes `az repos pr update` with `--title` and `--description` parameters, allowing the pipeline to synchronize PR content when changes occur on the source branch after initial creation.