Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Migrate from GitHub or Jenkins to Azure DevOps

By Kokil Thapa | Last reviewed: September 2026

Teams outgrow GitHub Actions or Jenkins when they need tighter work-item traceability, enterprise policy, or a single Microsoft stack. To migrate from GitHub or Jenkins to Azure DevOps, you map repos, pipelines, secrets, and agents first, then move in phases with a rollback path. I've maintained GitLab CI and Deployer 7 pipelines on shared EC2 for years; the same discipline applies here. This guide walks through inventory, import, YAML conversion, and cutover checks that keep production stable. Start with our Azure DevOps beginner guide if the platform is new to your team.

Why should you migrate from GitHub or Jenkins to Azure DevOps?

GitHub excels at open source and community workflows. Jenkins offers plugin flexibility on self-hosted hardware. Azure DevOps bundles Boards, Repos, Pipelines, Test Plans, and Artifacts under one identity and permission model.

Common triggers include a Microsoft/Azure estate, compliance needs for audit trails, or fatigue from Jenkins plugin upgrades and controller maintenance. On client projects I've seen Jenkins controllers become single points of failure after years of plugin drift.

Azure DevOps is not always the right move. Small teams on GitHub Actions with simple deploys may gain little. Heavy Jenkins Groovy logic can take weeks to rewrite. Budget for migration time before you commit.

Migration decision treeNeed Azure + audit?YesPlan Azure DevOpsNoStay on GitHubComplex JenkinsPilot one pipelineNever big-bang cutover without parallel runs
Decision tree before you migrate from GitHub or Jenkins to Azure DevOps — pilot first, cut over last.

Compare your current stack against Azure DevOps capabilities before you schedule work. The table below covers what teams ask about most often during planning calls.

CapabilityGitHub ActionsJenkinsAzure DevOps
Source controlGitHub reposAny Git remoteAzure Repos (Git or TFVC)
Pipeline formatYAML in .github/workflowsJenkinsfile (Declarative or Scripted)YAML in repo or classic UI
Work trackingGitHub Issues / ProjectsPlugin-dependent (Jira common)Azure Boards native
SecretsRepo/org secrets, OIDCCredentials store, pluginsVariable groups, Key Vault, service connections
Self-hosted runnersGitHub-hosted or self-hostedAgents on any OSMicrosoft-hosted or self-hosted agents
Artifact storageActions artifacts, packagesArchive to disk, Nexus, etc.Azure Artifacts feeds

For a deeper pipeline comparison, read our GitHub Actions vs Azure Pipelines guide. Teams already on Jira may also review integrating Jira with GitHub and Jenkins before they replatform work tracking.

How do you assess your current GitHub or Jenkins setup before migration?

Inventory drives timeline and risk. Skipping this step is the most common reason migrations stall mid-quarter.

Build the migration inventory spreadsheet

Document every repository, default branch, branch protection rules, and webhook targets. List every pipeline: Jenkins job name, trigger type, agent label, and downstream deploy step. Capture secret names without values — never paste credentials into tickets.

  1. Export Jenkins job configs with jenkins-cli or the Configuration as Code plugin where available.
  2. Export GitHub Actions workflow files from .github/workflows/ in each repo.
  3. Map external integrations: SonarQube, Slack, Snyk, Docker registries, cloud deploy targets.
  4. Identify scheduled jobs, cron triggers, and manual approval gates.
  5. Record agent OS, installed runtimes (Node.js 26 LTS, PHP 8.5, Composer 2.10), and disk paths used by builds.

Tag each pipeline as lift-and-shift, rewrite, or retire. Freestyle Jenkins jobs with Groovy spaghetti usually land in rewrite. Simple GitHub Actions that run composer install and PHPUnit often lift cleanly.

Use a JSON formatter to validate exported webhook payloads and API responses during inventory. For large estates, our custom software development service often includes migration planning alongside application work.

Set scope and rollback criteria

Pick one non-critical repo for a pilot. Define success: green build, artifact published, deploy to staging, rollback tested. Define failure: any secret leak, broken main branch, or deploy without approval.

Keep the old system running in parallel until two consecutive release cycles pass on Azure DevOps. Sister sites I maintain on Deployer 7 + GitLab CI follow the same parallel-run rule before DNS or webhook cutover.

How do you move repositories from GitHub to Azure Repos?

Azure Repos preserves Git history when you import correctly. TFVC-only legacy repos need a different path — this guide assumes Git.

Import via Azure DevOps UI

In Azure DevOps: Repos → Import repository → Git. Paste the GitHub HTTPS clone URL. Supply a personal access token with repo read scope. Azure DevOps clones all branches and tags into a new repo inside your project.

# Alternative: mirror push from a workstation with full history
git clone --mirror https://github.com/org/my-app.git
cd my-app.git
git remote add azure https://dev.azure.com/org/project/_git/my-app
git push azure --mirror

After import, verify tag count and latest commit SHA match GitHub. Run git log -1 on both remotes and compare hashes.

Branch policies and pull request workflow

Recreate branch protection from GitHub or Jenkins multi-branch settings in Azure Repos policies. Require pull request reviewers, link work items, and enable build validation against your new pipeline.

Our Azure Repos branch policies guide covers reviewer counts, path filters, and merge types. If your team used GitHub Actions status checks, map each check name to an Azure Pipelines policy requirement.

Repo migration flowGitHub repobranches + tagsMirror importPAT or SSHAzure Repossame SHAsBranch policiesPR + build gatesRetire GitHubafter parallel OKVerify: git log, tags, LFS objectsbefore webhook cutover
GitHub-to-Azure Repos import flow with verification gates before you retire the old remote.

Git LFS objects need explicit migration. Enable LFS on Azure Repos, then run git lfs fetch --all and git lfs push --all azure from a clone that has LFS installed. Missing LFS blobs break builds that reference large assets.

How do you convert Jenkins pipelines to Azure Pipelines YAML?

Jenkins Declarative syntax maps reasonably to Azure Pipelines YAML. Scripted Groovy with shared libraries often needs a full rewrite. GitHub Actions YAML translates faster because both systems use declarative step blocks.

Jenkins Declarative to Azure Pipelines

A typical Jenkinsfile with agent label, stages, and sh steps becomes a YAML file at azure-pipelines.yml in the repo root.

# Jenkins Declarative (source)
pipeline {
  agent { label 'linux-php' }
  stages {
    stage('Build') {
      steps { sh 'composer install --no-dev' }
    }
    stage('Test') {
      steps { sh 'vendor/bin/phpunit' }
    }
  }
}
# Azure Pipelines YAML (target)
trigger:
  branches:
    include: [ main ]

pool:
  name: 'linux-php'   # self-hosted agent pool name

steps:
  - script: composer install --no-dev
    displayName: 'Composer install'

  - script: vendor/bin/phpunit
    displayName: 'Run PHPUnit'

Map Jenkins post { always { cleanWs() } } blocks to clean: true on checkout tasks or explicit cleanup scripts. Map input approval steps to YAML environment approvals or manual validation jobs.

Multi-branch Jenkins jobs become separate pipeline definitions with branch filters, or one pipeline with conditional stages. Our Jenkins declarative pipeline tutorial helps teams document source syntax before conversion.

GitHub Actions to Azure Pipelines

Translate triggers first. GitHub on: push maps to trigger. Pull request triggers map to pr blocks in Azure Pipelines.

# GitHub Actions (source)
on: [ push, pull_request ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test
# Azure Pipelines (target)
trigger: [ main ]
pr: [ main ]

pool:
  vmImage: 'ubuntu-latest'

steps:
  - checkout: self
  - script: npm ci
    displayName: 'Install deps'
  - script: npm test
    displayName: 'Run tests'

GitHub Actions marketplace steps lack direct equivalents. Replace actions/cache with Cache@2 tasks. Replace actions/upload-artifact with PublishPipelineArtifact@1. For Laravel projects, see our GitHub Actions for Laravel testing and deploy article — the same test commands carry over; only the wrapper syntax changes.

Microsoft documents YAML schema at learn.microsoft.com/azure/devops/pipelines/yaml-schema. Jenkins pipeline syntax reference lives at jenkins.io pipeline syntax.

Pipeline conversion mapJenkinsfileDeclarativeGitHub Actionsworkflow YAMLRewrite YAMLazure-pipelines.ymlAzure Pipelinesrun + validateCommon mappingsagent / runs-on → poolstage / job → job + stagecredentials → variable group
Jenkins and GitHub Actions both converge on Azure Pipelines YAML — mapping agents, stages, and credentials is the core work.

How do you migrate secrets, agents, and deployment targets?

Secrets and agents cause most production incidents during CI/CD migration. Treat them as a dedicated workstream, not a footnote on pipeline conversion.

Secrets and service connections

Jenkins stores credentials in the credentials plugin or plain text in job configs — audit before export. GitHub stores org and repo secrets separately; list scopes per environment.

  • Create Azure DevOps variable groups for non-production secrets linked to Key Vault where possible.
  • Create service connections for Azure RM, Docker registries, SSH deploy targets, and Kubernetes clusters.
  • Mark pipeline variables as secret so logs mask values.
  • Rotate any secret that ever lived in a Jenkins console log or GitHub Actions output.

Our guide on using Azure Key Vault secrets in pipelines shows the AzureKeyVault@2 task pattern. Never commit secrets into YAML — reference groups by name instead.

Self-hosted agents

Jenkins agents and GitHub self-hosted runners map to Azure DevOps agent pools. Install the agent package on each build host, register against your organisation URL, and assign a pool name that matches YAML pool.name values.

Match installed tooling to what pipelines expect: PHP 8.5, Composer 2.10, Node.js 26 LTS, Docker CLI. A PHP version mismatch that passed on Jenkins will fail silently on a new agent until the first build runs.

Read self-hosted Azure DevOps agents for registration commands and service account hardening. For Linux hosts, our Linux system administration service covers agent provisioning on Ubuntu 22/24 servers.

Deployment and infrastructure pipelines

Deployer, SSH, kubectl, and Terraform steps from Jenkins post-build actions become Azure deployment jobs or template stages. Terraform pipelines often use remote state in Azure Storage — see Terraform with Azure DevOps pipelines for backend config and plan/apply gates.

On production Laravel apps I deploy with Deployer 7 over SSH. The Azure Pipelines equivalent is an SSH service connection plus a script step calling dep deploy production. Keep the same release directory layout; only the CI wrapper changes.

What should you validate after you migrate from GitHub or Jenkins to Azure DevOps?

Cutover is a test plan, not a calendar date. Run the checklist below across at least one full sprint before you disable the old system.

Parallel-run validation checklist

  1. Trigger the same commit on both old and new pipelines; compare build duration and artifact checksums.
  2. Confirm pull request builds block merge on failure, matching previous branch protection.
  3. Verify deployment webhooks hit staging, then production, with manual approval gates intact.
  4. Test scheduled nightly builds and cron syntax — Azure uses cron in YAML schedules blocks.
  5. Confirm notification integrations (Slack, Teams, email) fire on failure and success.
  6. Run a rollback deploy from Azure Pipelines to prove the path still works.

Update DNS, webhook URLs, and status badges only after parallel runs pass. GitHub commit status APIs and Jenkins build badges need replacing with Azure Pipelines badge URLs or shield.io equivalents.

Cutover validation gatesParallel CIPR gatesDeploy OKRetire oldSecrets rotated — no plaintext in job logsRollback tested from Azure PipelinesTwo release cycles green before decommissionPortfolio proof: Deployer sites on shared EC2 pipelines
Validation gates before you retire GitHub Actions or Jenkins — parallel runs and rollback tests are non-negotiable.

Document the new runbook for on-call engineers: where logs live, how to re-run failed stages, and how to queue a manual deployment. Link work items in Azure Boards so every production deploy traces to a ticket.

Projects like Notary Kathmandu and Translation Nepal run on shared Deployer 7 + GitLab CI infrastructure I maintain. The same operational habits — symlink releases, PHP-FPM reload after deploy, opcache invalidation — apply after any CI platform change. See Court Marriage In Nepal for another legal-tech portal where reliable deploy pipelines matter.

For broader DevOps planning, the DevOps roadmap for 2026 and DevOps engineer skills roadmap help teams sequence migration alongside cloud and IaC work. Budget-conscious startups in Nepal should also read budgeting AWS and Azure in NPR before expanding their Azure footprint.

If migration includes moving workloads to Azure App Service or AKS, pair pipeline work with deploy to AKS with Azure Pipelines or cloud hosting migration guidance. Full replatforming may warrant website migration services beyond CI/CD alone.

Key Takeaways

  • Inventory every repo, pipeline, secret, agent, and webhook before you migrate from GitHub or Jenkins to Azure DevOps.
  • Import Git history with mirror push or Azure Repos import; verify SHAs, tags, and LFS blobs before cutover.
  • Rewrite Jenkinsfile and GitHub Actions YAML into azure-pipelines.yml; map pools, stages, and cache tasks explicitly.
  • Move secrets to variable groups and Key Vault; rotate anything exposed in old build logs.
  • Run parallel pipelines for two release cycles; test rollback before decommissioning Jenkins or GitHub Actions.
  • Keep a written runbook and link deploys to Azure Boards work items for audit traceability.

People Also Ask

Can you keep GitHub repos and only move CI to Azure Pipelines?

Yes. Azure Pipelines supports GitHub as an external repository source. You connect the GitHub org via OAuth or a PAT, then define YAML pipelines that trigger on GitHub push and pull request events. This hybrid model suits teams that want Azure DevOps build agents and release gates without moving source control yet.

How long does a Jenkins to Azure DevOps migration take?

A single simple pipeline often converts in one to two days including testing. An estate with fifty Jenkins jobs, shared Groovy libraries, and custom plugins typically needs four to twelve weeks. Scripted pipelines with dynamic node allocation take the longest because they rarely translate line-for-line.

Does Azure DevOps replace GitHub Actions entirely?

Not automatically. GitHub Actions remains valid for open source and GitHub-native workflows. Teams migrate when they need Azure Boards integration, enterprise policy enforcement, Microsoft-hosted compliance features, or consolidated billing under an Azure DevOps organisation already licensed through Microsoft.

What happens to Jenkins build history after migration?

Build history stays on the Jenkins controller unless you export it. Azure DevOps starts fresh retention for new runs. Archive critical Jenkins logs and artifacts to blob storage before decommission if compliance requires historical records. Azure Pipelines retention policies control how long new run data persists.

Plan your Azure DevOps migration with a phased rollout

A clean migration is boring on launch day — that is the goal. Inventory first, pilot one repo, convert YAML, migrate secrets and agents, then run parallel builds until two release cycles pass green. That is how you migrate from GitHub or Jenkins to Azure DevOps without breaking production deploys or losing audit history.

Need help converting Jenkins jobs, GitHub Actions workflows, or self-hosted agents for a Laravel, PHP, or WordPress estate? Contact us to scope a phased migration, or explore support and maintenance services for post-cutover pipeline ownership. Browse the portfolio for production sites that rely on disciplined deploy automation, and visit kokil.com.np for more engineering guides.

Frequently Asked Questions

Teams usually move when they need tighter work-item traceability, enterprise policy, or a single Microsoft stack. GitHub suits open source and community workflows; Jenkins offers plugin flexibility on self-hosted hardware. Azure DevOps bundles Boards, Repos, Pipelines, Test Plans, and Artifacts under one identity and permission model. Common triggers include a Microsoft or Azure estate, compliance needs for audit trails, or fatigue from Jenkins plugin upgrades and controller maintenance. On client projects I have seen Jenkins controllers become single points of failure after years of plugin drift. Azure DevOps is not always the right move, but it fits organisations that want native work tracking and centralised pipeline governance.

Yes. Azure Pipelines supports GitHub as an external repository source via OAuth or a personal access token, with YAML pipelines triggering on GitHub push and pull request events.

No. Small teams on GitHub Actions with simple deploys may gain little, and heavy Jenkins Groovy logic can take weeks to rewrite.

Inventory drives timeline and risk, and skipping it is the most common reason migrations stall mid-quarter. Document every repository, default branch, branch protection rules, and webhook targets. List every pipeline with Jenkins job name, trigger type, agent label, and downstream deploy step. Capture secret names without values. Export Jenkins configs with jenkins-cli or Configuration as Code where available, and collect GitHub Actions files from each repo. Map external integrations such as SonarQube, Slack, Snyk, Docker registries, and cloud deploy targets. Record agent OS, installed runtimes, and tag each pipeline as lift-and-shift, rewrite, or retire.

Azure Repos preserves Git history when you import correctly; this guide assumes Git, not TFVC-only legacy repos. In Azure DevOps, go to Repos, Import repository, Git, paste the GitHub HTTPS clone URL, and supply a personal access token with repo read scope. Azure DevOps clones all branches and tags into a new repo. Alternatively, mirror from a workstation with git clone --mirror, add the Azure remote, and git push azure --mirror. After import, verify tag count and latest commit SHA match GitHub by comparing git log -1 on both remotes. Recreate branch protection and map GitHub Actions status checks to Azure Pipelines policy requirements.

Jenkins Declarative syntax maps reasonably to Azure Pipelines YAML in azure-pipelines.yml at the repo root. A Jenkinsfile with agent label, stages, and sh steps becomes trigger blocks, pool name matching your self-hosted agent pool, and script steps with displayName values. Map post always cleanWs blocks to clean true on checkout or explicit cleanup scripts. Map input approval steps to environment approvals or manual validation jobs. Multi-branch Jenkins jobs become separate pipeline definitions with branch filters, or one pipeline with conditional stages. Scripted Groovy with shared libraries often needs a full rewrite rather than a direct translation.

Translate triggers first: GitHub on push maps to trigger, and pull request triggers map to pr blocks in Azure Pipelines. A typical job with runs-on ubuntu-latest, actions/checkout, and run steps becomes pool vmImage ubuntu-latest, checkout self, and script steps with displayName labels. GitHub Actions marketplace steps lack direct equivalents. Replace actions/cache with Cache@2 tasks and actions/upload-artifact with PublishPipelineArtifact@1. For Laravel projects, the same test commands carry over; only the wrapper syntax changes. Microsoft documents the YAML schema at learn.microsoft.com/azure/devops/pipelines/yaml-schema.

Treat secrets and agents as a dedicated workstream, not a footnote on pipeline conversion. Audit Jenkins credentials and GitHub org or repo secrets before export. Create Azure DevOps variable groups for non-production secrets, linked to Key Vault where possible. Create service connections for Azure RM, Docker registries, SSH deploy targets, and Kubernetes clusters. Mark pipeline variables as secret so logs mask values, and rotate any secret that ever lived in a Jenkins console log or GitHub Actions output. Jenkins agents and GitHub self-hosted runners map to Azure DevOps agent pools. Install the agent package, register against your organisation URL, and assign a pool name matching YAML pool.name values.

Match installed tooling to what pipelines expect: PHP 8.5, Composer 2.10, Node.js 26 LTS, and Docker CLI. A PHP version mismatch that passed on Jenkins will fail silently on a new agent until the first build runs. Install the agent package on each build host, register against your organisation URL, and assign a pool name that matches azure-pipelines.yml pool.name values. For Linux hosts, agent provisioning on Ubuntu 22 or 24 servers follows the same hardening patterns as Jenkins agents. Read self-hosted Azure DevOps agents documentation for registration commands and service account hardening before you cut over production builds.

Deployer, SSH, kubectl, and Terraform steps from Jenkins post-build actions become Azure deployment jobs or template stages. On production Laravel apps I deploy with Deployer 7 over SSH; the Azure Pipelines equivalent is an SSH service connection plus a script step calling dep deploy production. Keep the same release directory layout; only the CI wrapper changes. Terraform pipelines often use remote state in Azure Storage with plan and apply gates. The operational habits remain the same: symlink releases, PHP-FPM reload after deploy, and opcache invalidation apply after any CI platform change.

Git LFS objects need explicit migration; missing LFS blobs break builds that reference large assets. Enable LFS on Azure Repos first. From a clone that has LFS installed, run git lfs fetch --all and git lfs push --all azure to copy every large file object to the new remote. Verify that assets referenced in your build still resolve before you retire the GitHub remote. Treat LFS verification as a gate in your import checklist alongside tag count and latest commit SHA comparison between GitHub and Azure Repos.

Cutover is a test plan, not a calendar date. Trigger the same commit on both old and new pipelines and compare build duration and artifact checksums. Confirm pull request builds block merge on failure, matching previous branch protection. Verify deployment webhooks hit staging then production with manual approval gates intact. Test scheduled nightly builds and cron syntax in YAML schedules blocks. Confirm Slack, Teams, and email notifications fire on failure and success. Run a rollback deploy from Azure Pipelines to prove the path still works. Update DNS, webhook URLs, and status badges only after parallel runs pass.

Keep the old system running in parallel until two consecutive release cycles pass on Azure DevOps, with rollback tested.

Pick one non-critical repo for a pilot. Define success as a green build, artifact published, deploy to staging, and rollback tested. Define failure as any secret leak, broken main branch, or deploy without approval. Sister sites I maintain on Deployer 7 and GitLab CI follow the same parallel-run rule before DNS or webhook cutover. Document the new runbook for on-call engineers: where logs live, how to re-run failed stages, and how to queue a manual deployment. Link work items in Azure Boards so every production deploy traces to a ticket for audit traceability.

Tag each pipeline in your inventory spreadsheet as lift-and-shift, rewrite, or retire. Freestyle Jenkins jobs with Groovy spaghetti usually land in rewrite. Simple GitHub Actions that run composer install and PHPUnit often lift cleanly into Azure Pipelines YAML with minimal changes. Export Jenkins job configs with jenkins-cli or the Configuration as Code plugin where available. Capture scheduled jobs, cron triggers, and manual approval gates separately because each needs explicit mapping to YAML schedules blocks or environment approvals. This classification drives realistic timeline estimates before you commit to a full estate migration.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: