- Article
Azure DevOps Services
This purpose of this guide is to help you migrate from Travis to Azure Pipelines. This guide describes shows how to translate from a Travis configuration to an Azure Pipelines configuration.
We need your help to make this guide better! Submit comments or contribute your changes directly.
Key differences
There are many differences between Travis and Azure Pipelines, including:
Travis builds have stages, jobs and phases, while Azure Pipelines has steps that can be arranged and executed in an arbitrary order or grouping that you choose.
Azure Pipelines allows job definitions and steps to be stored in separate YAML files in the same or a different repository, enabling steps to be shared across multiple pipelines.
Azure Pipelines provides full support for building and testing on Microsoft-managed Linux, Windows, and macOS images. For more information about hosted agents, see Microsoft-hosted agents.
Prerequisites
- A GitHub account where you can create a repository. Create one for free.
- An Azure DevOps organization. Create one for free.If your team already has one, then make sure you're an administrator of the Azure DevOps project that you want to use.
- An ability to run pipelines on Microsoft-hosted agents. You can either purchase a parallel job or you can request a free tier.
- Basic knowledge of Azure Pipelines. If you're new to Azure Pipelines, see the following to learn more about Azure Pipelines and how it works prior to starting your migration:
- Create your first pipeline
- Key concepts for new Azure Pipelines users
Language
Travis uses the language
keyword to identify the prerequisite buildenvironment to set up for your build. For example, to select Node.JS16.x:
.travis.yml
language: node_jsnode_js: - 16
Microsoft-hosted agents contain the SDKs for many languages by default. To use a specific language version, you may need to use a language selection taskto set up the environment.
For example, to select Node.JS 16.x:
azure-pipelines.yml
steps:- task: UseNode@1 inputs: version: '16.x'
Language mappings
The language
keyword in Travis implies both that versionof language tools be used and that many build steps be implicitlyperformed. In Azure Pipelines, you need to specify the commands that you want to run.
Here's a translation guide from the language
keyword to the commandsthat are executed automatically for the most commonly used languages:
Language | Commands |
---|---|
c cpp | ./configure make make install |
csharp | nuget restore [solution.sln] msbuild /p:Configuration=Release [solution.sln] |
clojure | lein deps lein test |
go | go get -t -v ./... make or go test |
java groovy | Gradle:gradle assemble gradle check Maven: Ant: |
node_js | npm install or npm ci or yarn npm test |
objective-c swift | pod install or bundle exec pod install xcodebuild -scheme [scheme] build test \| xcpretty |
perl | cpanm --quiet --installdeps --notest . Build.PL: Makefile.PL: Makefile: |
php | phpunit |
python | pip install -r requirements.txt |
ruby | bundle install --jobs=3 --retry=3 rake |
In addition, less common languages can be enabled but require anotherdependency installation step or execution inside a docker container:
Language | Commands |
---|---|
crystal | docker run -v $(pwd):/src -w /src crystallang/crystal shards install docker run -v $(pwd):/src -w /src crystallang/crystal crystal spec |
d | sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list sudo apt-get update sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring sudo apt-get update sudo apt-get install dmd-compiler dub dub test --compiler=dmd |
dart | wget https://dl-ssl.google.com/linux/linux_signing_key.pub -O - \| sudo apt-key add - wget https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list -O /etc/apt/sources.list.d/dart_stable.list sudo apt-get update sudo apt-get install dart /usr/lib/dart/bin/pub get /usr/lib/dart/bin/pub run test |
erlang | sudo apt-get install rebar rebar get-deps rebar compile rebar skip_deps=true eunit |
elixir | sudo apt-get install elixir mix local.rebar --force mix local.hex --force mix deps.get mix test |
haskell | sudo apt-get install cabal-install cabal install --only-dependencies --enable-tests cabal configure --enable-tests cabal build cabal test |
haxe | sudo apt-get install haxe yes \| haxelib install [hxml] haxe [hxml] |
julia | sudo apt-get install julia julia -e "using Pkg; Pkg.build(); end" julia --check-bounds=yes -e "Pkg; Pkg.test(coverage=true); end" |
nix | docker run -v $(pwd):/src -w /src nixos/nix nix-build |
perl6 | sudo apt-get install rakudo PERL6LIB=lib prove -v -r --exec=perl6 t/ |
rust | curl -sSf https://sh.rustup.rs | sh -s -- -y cargo build --verbose cargo test --verbose |
scala | echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | /etc/apt/sources.list.d/sbt.list sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 sudo apt-get update sudo apt-get install sbt sbt ++2.11.6 test |
smalltalk | docker run -v $(pwd):/src -w /src hpiswa/smalltalkci smalltalkci |
Multiple language selections
You can also configure an environment that supports buildingdifferent applications in multiple languages. For example, to ensure thebuild environment targets both Node.JS 16.x and Ruby 3.2 or better:
azure-pipelines.yml
steps:- task: UseNode@1 inputs: version: '8.x'- task: UseRubyVersion@0 inputs: versionSpec: '>= 3.2'
Phases
In Travis, steps are defined in a fixed set of named phases such asbefore_install
or before_script
. Azure Pipelines doesn't have named phases and steps can be grouped, named, and organized in whatever way makes sense for the pipeline.
For example:
.travis.yml
before_install: - npm install -g bowerinstall: - npm install - bower installscript: - npm run build - npm test
azure-pipelines.yml
steps:- script: npm install -g bower- script: npm install- script: bower install- script: npm run build- script: npm test
Alternatively, steps can be grouped together and optionally named:
azure-pipelines.yml
steps:- script: | npm install -g bower npm install bower install displayName: 'Install dependencies'- script: npm run build- script: npm test
Parallel jobs
Travis provides parallelism by letting you define a stage, whichis a group of jobs that are executed in parallel. A Travis build canhave multiple stages; once all jobs in a stage have completed, the next stage starts.
With Azure Pipelines, you can makeeach step or stage dependent on any other step. In this way, you specify whichsteps run serially, and which can run in parallel.So you can fan out with multiple steps run in parallel afterthe completion of one step, and then fan back in with a single step that runs afterward.This model gives you options to define complex workflows if necessary. For now, here'sa simple example:
For example, to run a build script, then upon its completion run both theunit tests and the integration tests in parallel, and once all tests havefinished, package the artifacts and then run the deploy to pre-production:
.travis.yml
jobs: include: - stage: build script: ./build.sh - stage: test script: ./test.sh unit_tests - script: ./test.sh integration_tests - stage: package script: ./package.sh - stage: deploy script: ./deploy.sh pre_prod
azure-pipelines.yml
jobs:- job: build steps: - script: ./build.sh- job: test1 dependsOn: build steps: - script: ./test.sh unit_tests- job: test2 dependsOn: build steps: - script: ./test.sh integration_tests- job: package dependsOn: - test1 - test2 script: ./package.sh- job: deploy dependsOn: package steps: - script: ./deploy.sh pre_prod
Advanced parallel execution
In Azure Pipelines you have more options and control over how you orchestrate your pipeline.
For example, a team has a set of fast-running unit tests, and another set of and slower integration tests. The team wants to begin creating the .ZIP file for a release as soon as the unit are completed because they provide high confidencethat the build provides a good package. But before they deploy to pre-production, they want to wait until all tests have passed:
In Azure Pipelines they can do it this way:
azure-pipelines.yml
jobs:- job: build steps: - script: ./build.sh- job: test1 dependsOn: build steps: - script: ./test.sh unit_tests- job: test2 dependsOn: build steps: - script: ./test.sh integration_tests- job: package dependsOn: test1 script: ./package.sh- job: deploy dependsOn: - test1 - test2 - package steps: - script: ./deploy.sh pre_prod
Step reuse
In Travis you can use matrices to run multiple executions across a singleconfiguration. In Azure Pipelines you can use matrices in the same way, but you can also implement configuration reuse with templates.
Example: Environment variable in a matrix
One of the most common ways to run several builds with a slight variationis to change the execution using environment variables. For example, yourbuild script can look for the presence of an environment variable and changethe way your software is built, or the way it's tested.
You can use a matrix to have run a build configuration severaltimes, once for each value in the environment variable. For example,to run a given script three times, each time with a different setting foran environment variable:
.travis.yml
os: osxenv: matrix: - MY_ENVIRONMENT_VARIABLE: 'one' - MY_ENVIRONMENT_VARIABLE: 'two' - MY_ENVIRONMENT_VARIABLE: 'three'script: echo $MY_ENVIRONMENT_VARIABLE
azure-pipelines.yml
pool: vmImage: 'macOS-latest'strategy: matrix: set_env_to_one: MY_ENVIRONMENT_VARIABLE: 'one' set_env_to_two: MY_ENVIRONMENT_VARIABLE: 'two' set_env_to_three: MY_ENVIRONMENT_VARIABLE: 'three'steps:- script: echo $(MY_ENVIRONMENT_VARIABLE)
Example: Language versions in a matrix
Another common scenario is to run against severaldifferent language environments. Travis supports an implicit definitionusing the language
keyword, while Azure Pipelines expects an explicittask to define how to configure that language version.
You can use the environment variable matrix options in Azure Pipelinesto enable a matrix for different language versions. For example, you canset an environment variable in each matrix variable that corresponds to thelanguage version that you want to use, then in the first step, use thatenvironment variable to run the language configuration task:
.travis.yml
os: linuxmatrix: include: - rvm: 2.3.7 - rvm: 2.4.4 - rvm: 2.5.1script: ruby --version
azure-pipelines.yml
vmImage: 'ubuntu-latest'strategy: matrix: ruby 2.3: ruby_version: '2.3.7' ruby 2.4: ruby_version: '2.4.4' ruby 2.5: ruby_version: '2.5.1'steps:- task: UseRubyVersion@0 inputs: versionSpec: $(ruby_version)- script: ruby --version
Example: Operating systems within a matrix
It's also common to run builds in multiple operating systems. Travissupports this definition using the os
keyword, while Azure Pipelineslets you configure the operating system by selecting the pool to run inusing the vmImage
keyword.
For example, you can set an environment variable in each matrix variablethat corresponds to the operating system image that you want to use. Thenyou can set the machine pool to the variable you've set:
.travis.yml
matrix: include: - os: linux - os: windows - os: osxscript: echo Hello, world!
azure-pipelines.yml
strategy: matrix: linux: imageName: 'ubuntu-latest' mac: imageName: 'macOS-latest' windows: imageName: 'windows-latest'pool: vmImage: $(imageName)steps:- script: echo Hello, world!
Success and failure handling
Travis allows you to specify steps that run when the build succeeds,using the after_success
phase, or when the build fails, using theafter_failure
phase. With Azure Pipelines you can define success and failureconditions based on the result of any step, which enables more flexibleand powerful pipelines.
.travis.yml
build: ./build.shafter_success: echo Success after_failure: echo Failed
azure-pipelines.yml
steps:- script: ./build.sh- script: echo Success condition: succeeded()- script: echo Failed condition: failed()
Advanced success and failure handling
In Azure Pipelines you can program a flexible set of dependencies andconditions for flow control between jobs.
You can configure jobs to run based on the success orfailure of previous jobs or based on environment variables.You can even configure jobs to always run,regardless of the success of other jobs.
For example, if you want to run a script when the build fails, but onlyif it's running as a build on the main branch:
azure-pipelines.yml
jobs:- job: build steps: - script: ./build.sh- job: alert dependsOn: build condition: and(failed(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) steps: - script: ./sound_the_alarms.sh
Predefined variables
Both Travis and Azure Pipelines set multiple environment variablesto allow you to inspect and interact with the execution environment of theCI system.
In most cases, there's an Azure Pipelines variable to matchthe environment variable in Travis. Here's a list of commonly usedenvironment variables in Travis and their analog in Azure Pipelines:
Travis | Azure Pipelines | Description |
---|---|---|
CI=true or TRAVIS=true | TF_BUILD=True | Indicates that your build is running in the CI system; useful for scripts that are also intended to be run locally during development. |
TRAVIS_BRANCH | CI builds:BUILD_SOURCEBRANCH Pull request builds: | The name of the branch the build was queued for, or the name of the branch the pull request is targeting. |
TRAVIS_BUILD_DIR | BUILD_SOURCESDIRECTORY | The location of your checked out source and the default working directory. |
TRAVIS_BUILD_NUMBER | BUILD_BUILDID | A unique numeric identifier for the current build invocation. |
TRAVIS_COMMIT | CI builds:BUILD_SOURCEVERSION | The commit ID currently being built. |
TRAVIS_COMMIT | Pull request builds:git rev-parse HEAD^2 | For pull request validation builds, Azure Pipelines sets BUILD_SOURCEVERSION to the resulting merge commit of the pull request into main; this command identifies the pull request commit itself. |
TRAVIS_COMMIT_MESSAGE | BUILD_SOURCEVERSIONMESSAGE | The log message of the commit being built. |
TRAVIS_EVENT_TYPE | BUILD_REASON | The reason the build was queued; a map of values is in the "build reasons" table below. |
TRAVIS_JOB_NAME | AGENT_JOBNAME | The name of the current job, if specified. |
TRAVIS_OS_NAME | AGENT_OS | The operating system that the job is running on; a map of values is in the "operating systems" table below. |
TRAVIS_PULL_REQUEST | Azure Repos:SYSTEM_PULLREQUEST_PULLREQUESTID GitHub: | The pull request number that triggered this build. (For GitHub builds, this is a unique identifier that is not the pull request number.) |
TRAVIS_PULL_REQUEST_BRANCH | SYSTEM_PULLREQUEST_SOURCEBRANCH | The name of the branch where the pull request originated. |
TRAVIS_PULL_REQUEST_SHA | Pull request builds:git rev-parse HEAD^2 | For pull request validation builds, Azure Pipelines sets BUILD_SOURCEVERSION to the resulting merge commit of the pull request into main; this command identifies the pull request commit itself. |
TRAVIS_PULL_REQUEST_SLUG | The name of the forked repository, if the pull request originated in a fork. There's no analog to this in Azure Pipelines. | |
TRAVIS_REPO_SLUG | BUILD_REPOSITORY_NAME | The name of the repository that this build is configured for. |
TRAVIS_TEST_RESULT | AGENT_JOBSTATUS | Travis sets this value to 0 if all previous steps have succeeded (returned 0 ). For Azure Pipelines, check that AGENT_JOBSTATUS=Succeeded . |
TRAVIS_TAG | BUILD_SOURCEBRANCH | If this build was queued by the creation of a tag then this is the name of that tag. For Azure Pipelines, the BUILD_SOURCEBRANCH is set to the full Git reference name, for example, refs/tags/tag_name . |
TRAVIS_BUILD_STAGE_NAME | The name of the stage in Travis. As we saw earlier, Azure Pipelines handles flow control using jobs. You can reference AGENT_JOBNAME . |
Build Reasons:
The TRAVIS_EVENT_TYPE
variable contains values that map to values provided by the Azure Pipelines BUILD_REASON
variable:
Travis | Azure Pipelines | Description |
---|---|---|
push | IndividualCI | The build is a continuous integration build from a push. |
pull_request | PullRequest | The build was queued to validate a pull request. |
api | Manual | The build was queued by the REST API or a manual request on the web page. |
cron | Schedule | The build was scheduled. |
Operating Systems:
The TRAVIS_OS_NAME
variable contains values that map to values provided by the Azure Pipelines AGENT_OS
variable:
Travis | Azure Pipelines | Description |
---|---|---|
linux | Linux | The build is running on Linux. |
osx | Darwin | The build is running on macOS. |
windows | Windows_NT | The build is running on Windows. |
For more information, see Predefined environment variables.
If there isn't a variable for the data you need, then you can use a shellcommand to get it. For example, a good substitute of an environmentvariable containing the commit ID of the pull request being built is torun a git command: git rev-parse HEAD^2
.
Building specific branches
By default, both Travis and Azure Pipelines perform CI builds on allbranches. Similarly, both systems allow you to limit these builds tospecific branches. In Azure Pipelines, the list of branches to buildshould be listed in the include
list and the branches not to buildshould be listed in the `exclude list. Wildcards are supported.
For example, to build only the main branch and those that begin withthe word "releases":
.travis.yml
branches: only: - main - /^releases.*/
azure-pipelines.yml
trigger: branches: include: - main - releases*
Output caching
Travis supports caching dependencies and intermediate build output to improvebuild times. Azure Pipelines doesn't support caching intermediate buildoutput, but does offer integration withAzure Artifactsfor dependency storage.
Git submodules
Travis and Azure Pipelines both clone git repos "recursively" bydefault. This means that submodules are cloned by the agent, whichis useful since submodules usually contain dependencies.However, the extra cloning takes time, so if you don't need the dependenciesthen you can disable cloning submodules:
.travis.yml
git: submodules: false
azure-pipelines.yml
checkout: submodules: false