Skip to content

Latest commit

 

History

History
669 lines (506 loc) · 18.1 KB

File metadata and controls

669 lines (506 loc) · 18.1 KB
render_with_liquid false

Azure Pipelines with GitHub Repositories: Impact Analysis After Migration

Executive Summary

When migrating repositories from Azure DevOps Repos to GitHub while continuing to use Azure Pipelines for CI/CD, organizations face significant challenges related to cross-repository references, pipeline templates, and service connections. This document provides a deep analysis of the impacts, challenges, and solutions for maintaining Azure Pipelines functionality after repository migration.


Table of Contents

  1. Understanding the Hybrid Model
  2. Critical Impact Areas
  3. Pipeline Template References
  4. Repository Resources and Checkout
  5. Service Connections Requirements
  6. Triggers and Automation Impact
  7. Authentication and Authorization
  8. Migration Scenarios and Solutions
  9. Step-by-Step Remediation Guide
  10. Best Practices and Recommendations

Understanding the Hybrid Model

The Scenario

Many organizations choose a phased migration approach:

  1. Phase 1: Migrate repositories from Azure DevOps Repos to GitHub
  2. Phase 2: Continue using Azure Pipelines for build/deploy (until GitHub Actions migration is complete)

This creates a hybrid model where:

  • Source code resides in GitHub
  • CI/CD pipelines remain in Azure Pipelines
  • Pipeline templates may reference repositories in both locations

Why This Matters

Azure Pipelines was designed to work seamlessly with Azure Repos. When you move repositories to GitHub:

  • Repository resource types change from git (Azure Repos) to github
  • Service connections become mandatory for GitHub repos
  • Trigger mechanisms work differently
  • Cross-repository template resolution changes

Critical Impact Areas

Impact Matrix

Area Impact Level Effort to Fix Description
Pipeline templates (extends, template) 🔴 High High All template references must be updated
Repository resources (checkout) 🔴 High Medium Multi-repo checkout requires service connections
CI/CD triggers 🟡 Medium Medium Trigger configuration differs for GitHub
Variable groups & secrets 🟢 Low Low No change needed
Artifact publishing 🟢 Low Low Works the same way
Service connections 🔴 High High New connections required for each GitHub repo

The Biggest Challenges

  1. Central Template Repositories: If you use a central repository for pipeline templates (common pattern), every pipeline that extends or includes templates from that repo must be updated.

  2. Resource Triggers: Repository resource triggers only work for Azure Repos Git - they do NOT work for GitHub repositories.

  3. Service Connection Proliferation: Each GitHub repository/organization requires a dedicated service connection.

  4. Simultaneous Updates Required: You cannot migrate repos one-by-one if they have interdependencies - templates and resources must be updated atomically.


Pipeline Template References

How Templates Work Today (Azure Repos)

# Current: Template in Azure Repos
resources:
  repositories:
    - repository: templates
      type: git                          # Azure Repos type
      name: MyProject/PipelineTemplates  # Project/Repo format

extends:
  template: ci-template.yml@templates

After Migration (GitHub)

# After: Template in GitHub
resources:
  repositories:
    - repository: templates
      type: github                                    # Changed type
      name: MyOrg/PipelineTemplates                   # Org/Repo format
      endpoint: GitHubServiceConnection               # Required!

extends:
  template: ci-template.yml@templates

Key Differences

Aspect Azure Repos (git) GitHub (github)
Type type: git type: github
Name format Project/Repository Organization/Repository
Service connection Optional (same org) Required
Default branch Uses pipeline's branch Defaults to refs/heads/main
Triggers Supported Not supported

Template Extends Pattern Impact

If you use the extends pattern for pipeline security (recommended by Microsoft):

# Central template repository (security-enforced)
# File: templates/secure-pipeline.yml
parameters:
- name: buildSteps
  type: stepList

stages:
- stage: Build
  jobs:
  - job: SecureBuild
    steps:
    - script: echo "Security scan starting"
    - ${{ parameters.buildSteps }}
    - script: echo "Security scan complete"

Impact: Every pipeline that extends this template must:

  1. Update the repository resource type to github
  2. Add a service connection reference
  3. Update the repository name format

Repository Resources and Checkout

Multi-Repo Checkout Before Migration

# Before: All repos in Azure DevOps
resources:
  repositories:
  - repository: tools
    type: git
    name: MyProject/BuildTools
  - repository: shared
    type: git
    name: MyProject/SharedLibraries

steps:
- checkout: self
- checkout: tools
- checkout: shared

Multi-Repo Checkout After Migration

# After: Repos migrated to GitHub
resources:
  repositories:
  - repository: tools
    type: github
    name: MyOrg/BuildTools
    endpoint: GitHubConnection
  - repository: shared
    type: github
    name: MyOrg/SharedLibraries
    endpoint: GitHubConnection

steps:
- checkout: self
- checkout: tools
- checkout: shared

Mixed Scenario (Partial Migration)

During migration, you may have repositories in both locations:

# Mixed: Some repos in Azure DevOps, some in GitHub
resources:
  repositories:
  # Already migrated to GitHub
  - repository: app-code
    type: github
    name: MyOrg/ApplicationCode
    endpoint: GitHubConnection
  
  # Still in Azure DevOps
  - repository: legacy-tools
    type: git
    name: MyProject/LegacyTools

steps:
- checkout: self
- checkout: app-code
- checkout: legacy-tools

⚠️ Warning: This mixed model works but is complex to maintain. Plan to migrate all related repositories together.


Service Connections Requirements

Types of GitHub Service Connections

Connection Type Use Case Recommendations
GitHub App CI/CD pipelines Recommended - Uses Azure Pipelines identity
OAuth Personal repos ⚠️ Uses personal GitHub identity
PAT Automation scenarios ⚠️ Security risk, avoid if possible

Creating a GitHub Service Connection

  1. Azure DevOps Portal → Project Settings → Service connections
  2. New service connection → GitHub
  3. Choose authentication type (GitHub App recommended)
  4. Authorize and configure repository access

GitHub App Authentication Benefits

  • Builds use Azure Pipelines identity (not personal identity)
  • Supports GitHub Checks for PR status
  • Better rate limiting handling
  • Can be configured for specific repositories only

Service Connection Authorization

# In pipeline YAML
resources:
  repositories:
  - repository: myrepo
    type: github
    name: MyOrg/MyRepo
    endpoint: MyGitHubServiceConnection  # Must be authorized for this pipeline

First-time authorization: When a pipeline first uses a GitHub repository, you may see:

  • "This pipeline needs permission to access a resource"
  • Click "Authorize resources" to grant access

Triggers and Automation Impact

🚨 Critical Limitation: Repository Resource Triggers

Repository resource triggers only work for Azure Repos Git repositories in the same organization. They do NOT work for GitHub or Bitbucket repository resources.

Microsoft Documentation

What This Means

Before (Azure Repos) - This worked:

resources:
  repositories:
  - repository: shared-lib
    type: git
    name: MyProject/SharedLibrary
    trigger:              # ✅ Triggers when SharedLibrary changes
      branches:
        include:
        - main
        - releases/*

# Pipeline runs when SharedLibrary repo is updated

After (GitHub) - This does NOT work:

resources:
  repositories:
  - repository: shared-lib
    type: github
    name: MyOrg/SharedLibrary
    endpoint: GitHubConnection
    trigger:              # ❌ IGNORED - GitHub triggers not supported
      branches:
        include:
        - main

# Pipeline does NOT run when SharedLibrary repo is updated

Alternative Solutions for Triggers

Option 1: Use GitHub Webhooks

Configure a webhook in GitHub to call Azure Pipelines:

resources:
  webhooks:
  - webhook: SharedLibraryUpdated
    connection: GitHubWebhookConnection
    filters:
    - path: repository.full_name
      value: MyOrg/SharedLibrary

Option 2: Use GitHub Actions to Trigger Azure Pipelines

# In GitHub: .github/workflows/trigger-azure-pipeline.yml
name: Trigger Azure Pipeline
on:
  push:
    branches: [main]

jobs:
  trigger:
    runs-on: ubuntu-latest
    steps:
    - name: Trigger Azure Pipeline
      uses: Azure/pipelines@v1
      with:
        azure-devops-project-url: https://dev.azure.com/MyOrg/MyProject
        azure-pipeline-name: 'My-Pipeline'
        azure-devops-token: ${{ secrets.AZURE_DEVOPS_PAT }}

Option 3: Scheduled Pipeline Runs

schedules:
- cron: "0 */4 * * *"  # Every 4 hours
  displayName: Regular sync
  branches:
    include:
    - main
  always: true

Authentication and Authorization

Personal Access Tokens (Classic) vs Fine-Grained PATs

For Azure Pipelines GitHub integration:

PAT Type Supported Notes
Classic PAT ✅ Yes Required scopes: repo, admin:repo_hook, read:user, user:email
Fine-grained PAT ⚠️ Limited May not work for all scenarios

Required Permissions for GitHub App

Permission Purpose
Write access to code Commit YAML files (optional)
Read access to metadata Fetch repo info
Read/write to checks Display build status
Read/write to pull requests PR validation

Cross-Organization Access

If your GitHub repos are in different organizations:

  • Create separate service connections per GitHub organization
  • Each connection requires authorization from that org's admin

Migration Scenarios and Solutions

Scenario 1: Central Template Repository Migration

Problem: You have a central PipelineTemplates repo that 50+ pipelines extend from.

Solution:

  1. Create GitHub service connection before migration
  2. Prepare all pipeline updates in branches
  3. Migrate template repo to GitHub
  4. Immediately deploy all pipeline updates
  5. No phased approach - must be atomic

Updated Pipeline Example:

# Before
resources:
  repositories:
  - repository: templates
    type: git
    name: CentralProject/PipelineTemplates

# After
resources:
  repositories:
  - repository: templates
    type: github
    name: MyGitHubOrg/PipelineTemplates
    endpoint: GitHub-CentralTemplates
    ref: refs/heads/main  # Pin to specific branch

extends:
  template: dotnet-ci.yml@templates

Scenario 2: Application with Shared Library Dependency

Problem: Application repo depends on a shared library repo for build-time resources.

Before:

resources:
  repositories:
  - repository: shared-lib
    type: git
    name: MyProject/SharedLibrary
    trigger:
      branches:
        include:
        - main

steps:
- checkout: self
- checkout: shared-lib
- script: |
    # Use files from shared-lib
    cp shared-lib/config/*.json src/

After:

resources:
  repositories:
  - repository: shared-lib
    type: github
    name: MyOrg/SharedLibrary
    endpoint: GitHubConnection
    # Note: trigger removed - not supported for GitHub

steps:
- checkout: self
- checkout: shared-lib
- script: |
    # Same usage - checkout paths preserved
    cp shared-lib/config/*.json src/

Workaround for Trigger:

  • Use GitHub Actions in SharedLibrary to trigger Azure Pipeline via webhook
  • Or use scheduled builds

Scenario 3: Monorepo with Multiple Pipelines

Problem: Single repo with multiple applications, each with its own pipeline.

Solution: Path-based triggers work for GitHub repos:

# Pipeline for Service A
trigger:
  branches:
    include:
    - main
  paths:
    include:
    - services/service-a/**
    - shared/**

pr:
  branches:
    include:
    - main
  paths:
    include:
    - services/service-a/**

Step-by-Step Remediation Guide

Pre-Migration Checklist

  • Inventory all pipelines that reference the repos being migrated
  • Identify template dependencies - which pipelines use extends or template from other repos
  • Create GitHub service connections in advance
  • Test service connections with a sample pipeline
  • Document current trigger configurations (CI, PR, resource triggers)
  • Plan for resource triggers that won't work after migration

Migration Steps

Step 1: Create GitHub Service Connection

Azure DevOps → Project Settings → Service connections → New → GitHub

Choose Azure Pipelines GitHub App (recommended)

Step 2: Update Repository Resource Definitions

Find and replace pattern:

# Find (Azure Repos pattern)
- repository: <alias>
  type: git
  name: <Project>/<Repo>

# Replace with (GitHub pattern)
- repository: <alias>
  type: github
  name: <GitHubOrg>/<Repo>
  endpoint: <ServiceConnectionName>

Step 3: Update Triggers

For CI triggers (push to main repo): No change needed - works the same.

For PR triggers: No change needed - works the same.

For resource triggers: Remove and implement alternative (webhook/GitHub Action).

Step 4: Test in Non-Production

  1. Create test branch with updated pipeline YAML
  2. Run manual pipeline to verify checkout works
  3. Verify template resolution succeeds
  4. Test PR trigger behavior

Step 5: Deploy Changes

Deploy all pipeline changes simultaneously if they share template dependencies.

Post-Migration Verification

  • CI triggers work on push
  • PR triggers work on pull requests
  • Templates resolve correctly
  • Multi-repo checkout works
  • Artifacts publish correctly
  • GitHub Checks status appears on commits/PRs

Best Practices and Recommendations

1. Use GitHub App Authentication

# Recommended: Uses Azure Pipelines identity
resources:
  repositories:
  - repository: code
    type: github
    name: MyOrg/MyApp
    endpoint: AzurePipelines-GitHubApp  # GitHub App connection

2. Pin Template References

Always pin to a specific ref to avoid unexpected changes:

resources:
  repositories:
  - repository: templates
    type: github
    name: MyOrg/PipelineTemplates
    endpoint: GitHubConnection
    ref: refs/tags/v2.0.0  # Pin to tag
    # or
    ref: refs/heads/release/stable  # Pin to branch

3. Centralize Service Connection Management

  • Use consistent naming conventions for service connections
  • Document which pipelines use which connections
  • Implement least-privilege access (connection per repository when needed)

4. Plan for Trigger Limitations

Before migration, identify all resource triggers and plan alternatives:

Current Trigger Alternative
Resource trigger on library repo GitHub Actions → Azure Pipeline webhook
Resource trigger on shared config Scheduled builds + caching
Multi-repo trigger Webhook-based triggers

5. Test Extensively Before Production

# Use a test pipeline to verify configuration
trigger: none  # Manual only for testing

resources:
  repositories:
  - repository: migrated-repo
    type: github
    name: MyOrg/MigratedRepo
    endpoint: TestGitHubConnection

steps:
- checkout: migrated-repo
- script: |
    echo "Checkout succeeded"
    ls -la $(Build.SourcesDirectory)

6. Document Your Migration

Create a tracking document with:

  • All repos being migrated
  • All pipelines affected
  • Service connections created
  • Trigger changes required
  • Dependencies between pipelines
  • Rollback plan

Summary: Key Takeaways

Aspect Impact Action Required
Repository type Must change from git to github Update all pipeline YAML
Service connections Mandatory for GitHub repos Create before migration
Template references Must include endpoint Update all extends/template references
Resource triggers Not supported for GitHub Implement webhooks or alternatives
CI/PR triggers Work normally No change needed
Multi-repo checkout Works with service connection Add endpoint to resources

Migration Success Criteria

✅ All pipelines build successfully
✅ Templates resolve from GitHub
✅ Multi-repo checkout works
✅ CI triggers fire on push
✅ PR validation triggers fire
✅ GitHub Checks status displayed
✅ No "resource not authorized" errors


References