Azure Devops To Github

Azure Devops To Github

Reading time1 min
#DevOps#CI/CD#Cloud#GitHubActions#AzureDevOps#PipelineMigration

Seamless Migration: Transitioning Azure DevOps Pipelines to GitHub Actions—Maintaining Agility at Scale

Moving pipelines from Azure DevOps to GitHub Actions often surfaces during ecosystem consolidation, compliance, or when aiming for deeper integration with modern developer workflows. The goal: replicate, then enhance existing automation—without introducing friction or delay in delivery. Disruption is not inevitable.

Where Azure Pipelines and GitHub Actions Diverge

Feature AreaAzure PipelinesGitHub Actions
Task LibraryPre-built Microsoft tasks (DotNetCoreCLI)Extensive open-action marketplace, shell native
Pipeline YAMLazure-pipelines.yml.github/workflows/*.yml
Secrets ManagementLibrary, variable groupsEncrypted secrets per-repo/org
Work ReuseTemplates, shared YAMLReusable workflows, composite actions
ApprovalsEnvironment gates, classic approvalsEnvironments with reviewers, PR checks

1. Audit Existing Azure Pipelines

Inventory is non-negotiable. Start by exporting pipeline YAMLs (both build and release if using classic). Key information:

  • Triggers: Are builds scheduled (cron), on push, or PR only?
  • Tasks: Identify both standardized (e.g., DotNetCoreCLI@2) and custom scripts.
  • Environments and Approvals: Note any manual interventions, agent pools, and artifact publish points.
  • Secrets/Variables: Document references to groups, key vault, or pipeline variables.

Typical snippet:

trigger:
  branches:
    include:
      - main

pool:
  vmImage: 'ubuntu-22.04'

steps:
  - script: |
      echo "Compiling solution"
  - task: DotNetCoreCLI@2
    inputs:
      command: 'build'
      projects: '**/*.csproj'

Gotcha: Not all Azure tasks have a one-to-one match in GitHub Actions. Some (e.g., SonarCloud integration) may require different configuration or marketplace actions.


2. Establish Baseline Workflow in GitHub Actions

Build a minimal equivalent using .github/workflows/ci.yml. Always add explicit checkout—unlike Azure, GitHub workflow doesn’t provide source by default.

name: Build

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v3

      - name: Build .NET
        run: dotnet build "**/*.csproj"

Note: Error handling changes—GitHub steps fail the job unless continued via continue-on-error: true, unlike Azure which may have more granular controls.

  • Azure’s DotNetCoreCLI@2 maps to native shell commands in Actions.
  • Logs differ in verbosity. GitHub can stream output but masks secrets aggressively, which sometimes obscures debug info.

3. Port and Refactor Secrets Handling

Azure’s variable groups need flattening: each secret moves to GitHub repository or org-level secrets. For complex orgs, automate with gh CLI.

Access in workflow:

env:
  CONNECTION_STRING: ${{ secrets.SQL_CONN }}

steps:
  - name: Check connection
    run: |
      echo "$CONNECTION_STRING"

Known Issue: Secret masking in logs. Any echo of long multiline secrets tends to be replaced mid-line—leads to confusion. Use base64 encoding for binary blobs, decode in step.


4. Standardize Via Reusable Workflows or Composite Actions

Avoid copy-pasta by centralizing repeated job patterns.

build-dotnet.yml workflow (called by others):

name: DotNet Build

on:
  workflow_call:
    inputs:
      buildArgs:
        required: false
        type: string

jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v3
      - run: dotnet build ${{ inputs.buildArgs }}

Caller:

jobs:
  build:
    uses: ./.github/workflows/build-dotnet.yml
    with:
      buildArgs: '--configuration Release'

Practical tip: Internal reusable workflows are still in growth phase—distribute as public actions if you need genuine cross-repo reuse.


5. Implement PR Triggers and Gates

Actions natively links workflow checks to pull requests—status appears in the GitHub UI. Sample configuration:

on:
  pull_request:
    branches:
      - main

jobs:
  validate:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v3
      - run: dotnet test --verbosity normal

Environment protection: Add required reviewers for environments:

  1. Under Settings → Environments → production, set reviewers.

  2. Reference in workflow:

    jobs:
      deploy:
        runs-on: ubuntu-22.04
        environment:
          name: production
          url: https://prod.example.com
        steps:
          - run: ./deploy.sh
    

Job execution will pause until reviewers approve on the UI. Delays are possible if notification settings aren’t tuned, so warn teams in advance.


6. Optimize With Matrix Builds

Matrix jobs can parallelize test/release on OS and language matrixes. Immediate benefit: cut down CI time if, for example, supporting both Windows and Ubuntu.

jobs:
  matrix-test:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-22.04, windows-2022]
        dotnet-version: ['6.0.x', '7.0.x']

    steps:
      - uses: actions/checkout@v3
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: ${{ matrix.dotnet-version }}
      - run: dotnet test --no-build

Side Effect: Cost—matrix runs use parallel runners. On public repos, free minutes go quickly. For complex matrices, split to only the most relevant axes.


Cutting Corners: What Breaks and What Doesn't

  • Artifacts: publish in Azure is actions/upload-artifact in GitHub. Retention policy is stricter—default is 90 days unless configured.
  • Classic release pipelines: Require re-architecting—no direct migration path.
  • Multi-repo triggers: In GitHub, supported only with repository dispatch, which isn’t as seamless as Azure’s cross-pipeline triggering.
  • Self-hosted agents: Reusable; both platforms support self-hosting, but setup scripts and registration differ.

Closing Observations

Treat migration as an exercise in process improvement, not just translation. Dev workflow will change—sometimes subtly (how secrets are surfaced), sometimes radically (transition to workflow-centric gates, decoupled deploy logic).

Best results come from incremental refactoring:

  • Migrate a single small project, smoke-test workflows, and gather error logs.
  • Document permission model changes—GitHub's token scoping and fork PR behaviors often surprise teams.
  • Invest early in reusable actions or workflow libraries if you anticipate scaling.

Not all functionality travels cleanly, but new GitHub-native features (job dependencies, step outputs, richer artifact actions) often offset migration overhead. Legacy pipelines lingering in Azure? Sometimes best to sunset rather than port.


Resources

(Engineered by [Your Name], DevOps Lead—Azure/GitHub Migrations Team)