Build pipeline triggers

Azure Pipelines | Azure DevOps Server 2019 | TFS 2018 | TFS 2017 | TFS 2015

Note

In Microsoft Team Foundation Server (TFS) 2018 and previous versions, run and release pipelines are called definitions, runs are called builds, service connections are called service endpoints, stages are called environments, and jobs are called phases.

On the Triggers tab, you specify the events that trigger the build. You can use the same build pipeline for both CI and scheduled builds.

CI triggers

Continuous integration (CI) triggers cause a build to run whenever a push is made to the specified branches or a specified tag is pushed.

YAML builds are configured by default with a CI trigger on all branches.

YAML builds are configured by default with a CI trigger on all branches.

Branches

You can control which branches get CI triggers with a simple syntax:

trigger:
- master
- releases/*

You can specify the full name of the branch (for example, master) or a wildcard (for example, releases/*). See Wildcards for information on the wildcard syntax. Note: you cannot use variables in triggers, as variables are evaluated at runtime (after the trigger has fired).

You can specify branches to include and exclude. For example:

# specific branch build
trigger:
  branches:
    include:
    - master
    - releases/*
    exclude:
    - releases/old*

In addition to specifying branch names in the branches lists, you can also configure triggers based on tags by using the following format:

trigger:
  branches:
    include:
      refs/tags/{tagname}
    exclude:
      refs/tags/{othertagname}

If you don't specify any triggers, the default is as if you wrote:

trigger:
  branches:
    include:
    - '*'  # must quote since "*" is a YAML reserved character; we want a string

Important

When you specify a trigger, it replaces the default implicit trigger, and only pushes to branches that are explicitly configured to be included will trigger a pipeline. Includes are processed first, and then excludes are removed from that list. If you specify an exclude but don't specify any includes, nothing will trigger.

Batching CI builds

If you have a lot of team members uploading changes often, you may want to reduce the number of builds you're running. If you set batch to true, when a build is running, the system waits until the build is completed, then queues another build of all changes that have not yet been built.

# specific branch build with batching
trigger:
  batch: true
  branches:
    include:
    - master

Paths

You can specify file paths to include or exclude. Note that the wildcard syntax is different between branches/tags and file paths.

# specific path build
trigger:
  branches:
    include:
    - master
    - releases/*
  paths:
    include:
    - docs/*
    exclude:
    - docs/README.md

When you specify paths, you also need to explicitly specify branches to trigger on.

Tags

In addition to specifying tags in the branches lists as covered in the previous section, you can directly specify tags to include or exclude:

# specific branch build
trigger:
  tags:
    include:
    - v2.*
    exclude:
    - v2.0

If you don't specify any tag triggers, then by default, tags will not trigger pipelines.

Note

If you specify tags in combination with branch filters that include file paths, the trigger will fire if the branch filter is satisfied and either the tag or the path filter is satisfied.

Note

Triggering on tags is not currently supported for Bitbucket Cloud repos.

Opting out of CI builds

Disabling the CI trigger

You can opt out of CI builds entirely by specifying trigger: none.

# A pipeline with no CI trigger
trigger: none

Important

When you push a change to a branch, the YAML file in that branch is evaluated to determine if a CI build should be run.

For more information, see Triggers in the YAML schema.

Skipping CI for individual commits

You can also tell Azure Pipelines to skip running a pipeline that a commit would normally trigger. Just include ***NO_CI*** in the commit message of the HEAD commit and Azure Pipelines will skip running CI. This is supported for commits to Azure Repos Git and GitHub.

You can also tell Azure Pipelines to skip running a pipeline that a commit would normally trigger. Just include [skip ci] in the commit message or description of the HEAD commit and Azure Pipelines will skip running CI. You can also use any of the variations below. This is supported for commits to Azure Repos Git, Bitbucket Cloud, GitHub, and GitHub Enterprise Server.

  • [skip ci] or [ci skip]
  • skip-checks: true or skip-checks:true
  • [skip azurepipelines] or [azurepipelines skip]
  • [skip azpipelines] or [azpipelines skip]
  • [skip azp] or [azp skip]
  • ***NO_CI***

YAML builds are not yet available on TFS.

PR triggers

Pull request (PR) triggers cause a build to run whenever a pull request is opened with one of the specified target branches, or when changes are pushed to such a pull request.

Important

YAML PR triggers are only supported in GitHub and Bitbucket Cloud. If you are using Azure Repos Git, you can configure a branch policy for build validation in order to trigger your build pipeline for validation.

Note

New pipelines automatically override YAML PR triggers with a setting in the UI. To opt into YAML-based control, you need to disable this setting on the Triggers tab in the UI.

Important

YAML PR triggers are only supported in GitHub. If you are using Azure Repos Git, you can configure a branch policy for build validation in order to trigger your build pipeline for validation.

You can specify the target branches for your pull request builds. For example, to run pull request builds only for source branches in a PR that target master and releases/*, you can use the following pr trigger. This configuration triggers a build upon creation of any pull request where the target branch is set to the master or releases/* branches. The pipeline also triggers once with any commit coming into the source branch when the target branch is set to be master or releases/*, while the pull request is active.

pr:
- master
- releases/*

PR triggers will fire for these branches once the pipeline YAML file has reached that branch. For example, if you add master in a topic branch, PRs to master will not start automatically building. When the changes from the topic branch are merged into master, then the trigger will be fully configured.

If no pr triggers appear in your YAML file, pull request builds are automatically enabled for all branches, as if you wrote the following pr trigger. This configuration triggers a build when any pull request is created, and when commits come into the source branch of any active pull request.

pr:
  branches:
    include:
    - '*'  # must quote since "*" is a YAML reserved character; we want a string

Important

When you specify a pr trigger, it replaces the default implicit pr trigger, and only pushes to branches that are explicitly configured to be included will trigger a pipeline. Includes are processed first, and then excludes are removed from that list. If you specify an exclude but don't specify any includes, nothing will trigger.

You can specify the full name of the branch (for example, master) or a wildcard (for example, releases/*). See Wildcards for information on the wildcard syntax.

You can specify branches to include and exclude. For example:

# specific branch build
pr:
  branches:
    include:
    - master
    - releases/*
    exclude:
    - releases/old*

You can specify file paths to include or exclude. For example:

# specific path build
pr:
  branches:
    include:
    - master
    - releases/*
  paths:
    include:
    - docs/*
    exclude:
    - docs/README.md

Note that the wildcard syntax is different between branches/tags and file paths.

You can specify whether additional pushes to a PR should cancel in-progress runs for the same PR. The default is true.

# auto cancel false
pr:
  autoCancel: false
  branches:
    include:
    - master

You can opt out of pull request builds entirely by specifying pr: none.

# no PR builds
pr: none

Important

When you create a pull request, or push a change to the source branch of a PR, the YAML file in the source branch is evaluated to determine if a PR build should be run.

For more information, see PR trigger in the YAML schema.

Note

If your pr trigger isn't firing, ensure that you have not overridden YAML PR triggers in the UI. For more information, see Overriding YAML triggers.

YAML builds are not yet available on TFS.

Trigger builds using GitHub pull request comments

If your team uses GitHub pull requests, you can manually trigger pipelines using pull request comments. See details here.

Scheduled triggers

Important

Scheduled triggers defined using the pipeline settings UI take precedence over YAML scheduled triggers.

If your YAML pipeline has both YAML scheduled triggers and UI defined scheduled triggers, only the UI defined scheduled triggers are run. To run the YAML defined scheduled triggers in your YAML pipeline, you must remove the scheduled triggers defined in the pipeline setting UI. Once all UI scheduled triggers are removed, a push must be made in order for the YAML scheduled triggers to start running.

Scheduled triggers cause a build to run on a schedule defined using cron syntax.

schedules:
- cron: string # cron syntax defining a schedule
  displayName: string # friendly name given to a specific schedule
  branches:
    include: [ string ] # which branches the schedule applies to
    exclude: [ string ] # which branches to exclude from the schedule
  always: boolean # whether to always run the pipeline or only if there have been source code changes since the last run. The default is false.

In the following example, two schedules are defined.

schedules:
- cron: "0 0 * * *"
  displayName: Daily midnight build
  branches:
    include:
    - master
    - releases/*
    exclude:
    - releases/ancient/*
- cron: "0 12 * * 0"
  displayName: Weekly Sunday build
  branches:
    include:
    - releases/*
  always: true

The first schedule, Daily midnight build, runs a pipeline at midnight every day, but only if the code has changed since the last run, for master and all releases/* branches, except those under releases/ancient/*.

The second schedule, Weekly Sunday build, runs a pipeline at noon on Sundays, whether the code has changed or not since the last run, for all releases/* branches.

Note

The time zone for cron schedules is UTC, so in these examples, the midnight build and the noon build are at midnight and noon in UTC.

Scheduled triggers are evaluated for a branch when the following events occur.

  • A pipeline is created.
  • A pipeline's YAML file is updated, either from a push, or by editing it in the pipeline editor.
  • A new branch is created.

After one of these events occurs in a branch, any scheduled builds for that branch are added, if that branch matches the branch filters for the scheduled triggers contained in the YAML file in that branch.

Important

Scheduled builds for a branch are added only if the branch matches the branch filters for the scheduled triggers in the YAML file in that particular branch.

Example of scheduled triggers for multiple branches

For example, a pipeline is created with the following schedule, and this version of the YAML file is checked into the master branch. This schedule builds the master branch on a daily basis.

# YAML file in the master branch
schedules:
- cron: "0 0 * * *"
  displayName: Daily midnight build
  branches:
    include:
    - master

Next, a new branch is created based off of master, named new-feature. The scheduled triggers from the YAML file in the new branch are read, and since there is no match for the new-feature branch, no changes are made to the scheduled builds, and the new-feature branch is not built using a scheduled trigger.

If new-feature is added to the branches list and this change is pushed to the new-feature branch, the YAML file is read, and since new-feature is now in the branches list, a scheduled build is added for the new-feature branch.

# YAML file in the new-feature-branch
schedules:
- cron: "0 0 * * *"
  displayName: Daily midnight build
  branches:
    include:
    - master
    - new-feature

Now consider that a branch named release is created based off master, and then release is added to the branch filters in the YAML file in the master branch, but not in the newly created release branch.

# YAML file in the release branch
schedules:
- cron: "0 0 * * *"
  displayName: Daily midnight build
  branches:
    include:
    - master

# YAML file in the master branch with release added to the branches list
schedules:
- cron: "0 0 * * *"
  displayName: Daily midnight build
  branches:
    include:
    - master
    - release

Because release was added to the branch filters in the master branch, but not to the branch filters in the release branch, the release branch won't be built on that schedule. Only when the feature branch is added to the branch filters in the YAML file in the feature branch will the scheduled build be added to the scheduler.

Supported cron syntax

Each cron expression is a space-delimited expression with five entries in the following order.

mm HH DD MM DW
 \  \  \  \  \__ Days of week
  \  \  \  \____ Months
   \  \  \______ Days
    \  \________ Hours
     \__________ Minutes
Field Accepted values
Minutes 0 through 59
Hours 0 though 23
Days 1 through 31
Months 1 through 12, full English names, first three letters of English names
Days of week 0 through 6 (starting with Sunday), full English names, first three letters of English names

Values can be in the following formats.

Format Example Description
Wildcard * Matches all values for this field
Single value 5 Specifies a single value for this field
Comma delimited 3,5,6 Specifies multiple values for this field. Multiple formats can be combined, like 1,3-6
Ranges 1-3 The inclusive range of values for this field
Intervals */4 or 1-5/2 Intervals to match for this field, such as every 4th value or the range 1-5 with a step interval of 2
Example Cron expression
Build every Monday, Wednesday, and Friday at 6:00 PM 0 18 * * Mon,Wed,Fri, 0 18 * * 1,3,5, 0 18 * * Mon,Wed,Fri, or 0 18 * * 1-5/2
Build every 6 hours 0 0,6,12,18 * * *, 0 */6 * * *, or 0 0-18/6 * * *
Build every 6 hours starting at 9:00 AM 0 9,15,21 * * * or 0 9-21/6 * * *

For more information on supported formats, see Crontab Expression.

Note

Each cron schedule has a maximum of 100 pipeline runs per week. If you need more, you can split your cron schedule into multiple cron schedules that each result in 100 or less pipeline runs per week.

Migrating from the classic editor

The following examples show you how to migrate your schedules from the classic editor to YAML.

Example: Nightly build of Git repo in multiple time zones

In this example, the classic editor scheduled trigger has two entries, producing the following builds.

  • Every Monday - Friday at 3:00 AM (UTC + 5:30 time zone), build branches that meet the features/india/* branch filter criteria

    Scheduled trigger UTC + 5:30 time zone

  • Every Monday - Friday at 3:00 AM (UTC - 5:00 time zone), build branches that meet the features/nc/* branch filter criteria

    Scheduled trigger UTC -5:00 time zone

The equivalent YAML scheduled trigger is:

schedules:
- cron: "30 21 * * Sun-Thu"
  displayName: M-F 3:00 AM (UTC + 5:30) India daily build
  branches:
    include:
    - /features/india/*
- cron: "0 8 * * Mon-Fri"
  displayName: M-F 3:00 AM (UTC - 5) NC daily build
  branches:
    include:
    - /features/nc/*

In the first schedule, M-F 3:00 AM (UTC + 5:30) India daily build, the cron syntax (mm HH DD MM DW) is 30 21 * * Sun-Thu.

  • Minutes and Hours - 30 21 - This maps to 21:30 UTC, or 9:30 PM UTC. Since the specified time zone in the classic editor is UTC + 5:30, we need to subtract 5 hours and 30 minutes from the desired build time of 3:00 AM to arrive at the desired UTC time to specify for the YAML trigger.
  • Days and Months are specified as wildcards since this schedule doesn't specify to run only on certain days of the month, or on a specific month.
  • Days of the week - Sun-Thu - because of the timezone conversion, for our builds to run at 3:00 AM in the UTC + 5:30 India time zone, we need to specify starting them the previous day in UTC time. We could also specify the days of the week as 0-4 or 0,1,2,3,4.

In the second schedule, M-F 3:00 AM (UTC - 5) NC daily build, the cron syntax is 0 8 * * Mon-Fri.

  • Minutes and Hours - 0 8 - This maps to 8:00 AM UTC. Since the specified time zone in the classic editor is UTC - 5:00, we need to add 5 hours from the desired build time of 3:00 AM to arrive at the desired UTC time to specify for the YAML trigger.
  • Days and Months are specified as wildcards since this schedule doesn't specify to run only on certain days of the month, or on a specific month.
  • Days of the week - Mon-Fri - Because our timezone conversions don't span multiple days of the week for our desired schedule, we don't need to do any conversion here. We could also specify the days of the week as 1-5 or 1,2,3,4,5.

Important

The UTC time zones in YAML scheduled triggers don't account for daylight savings time.

Example: Nightly build with different frequencies

In this example, the classic editor scheduled trigger has two entries, producing the following builds.

  • Every Monday - Friday at 3:00 AM UTC, build branches that meet the master and releases/* branch filter criteria

    scheduled trigger different frequencies

  • Every Sunday at 3:00 AM UTC, build the releases/lastversion branch, even if the source or pipeline hasn't changed

    scheduled trigger different frequencies

The equivalent YAML scheduled trigger is:

schedules:
- cron: "0 3 * * Mon-Fri"
  displayName: M-F 3:00 AM (UTC) daily build
  branches:
    include:
    - master
    - /releases/*
- cron: "0 3 * * Sun"
  displayName: Sunday 3:00 AM (UTC) weekly latest version build
  branches:
    include:
    - /releases/lastversion
  always: true

In the first schedule, M-F 3:00 AM (UTC) daily build, the cron syntax is 0 3 * * Mon-Fri.

  • Minutes and Hours - 0 3 - This maps to 3:00 AM UTC. Since the specified time zone in the classic editor is UTC, we don't need to do any time zone conversions.
  • Days and Months are specified as wildcards since this schedule doesn't specify to run only on certain days of the month, or on a specific month.
  • Days of the week - Mon-Fri - because there is no timezone conversion, the days of the week map directly from the classic editor schedule. We could also specify the days of the week as 1,2,3,4,5.

In the second schedule, Sunday 3:00 AM (UTC) weekly latest version build, the cron syntax is 0 3 * * Sun.

  • Minutes and Hours - 0 3 - This maps to 3:00 AM UTC. Since the specified time zone in the classic editor is UTC, we don't need to do any time zone conversions.
  • Days and Months are specified as wildcards since this schedule doesn't specify to run only on certain days of the month, or on a specific month.
  • Days of the week - Sun - Because our timezone conversions don't span multiple days of the week for our desired schedule, we don't need to do any conversion here. We could also specify the days of the week as 0.
  • We also specify always: true since this build is scheduled to run whether or not the source code has been updated.

Scheduled builds are not yet supported in YAML syntax. After you create your YAML build pipeline, you can use pipeline settings to specify a scheduled trigger.

YAML builds are not yet available on TFS.

TFVC gated check-in

If your code is in a Team Foundation version control (TFVC) repo, use gated check-in to protect against breaking changes.

By default Use workspace mappings for filters is selected. Builds are triggered whenever a change is checked in under a path specified in your mappings in the source repository settings.

Otherwise, you can clear this check box and specify the paths in the trigger.

How it affects your developers

When developers try to check-in, they are prompted to build their changes.

Gated check-in prompt

The system then creates a shelveset and builds it.

For details on the gated check-in experience, see Check in to a folder that is controlled by a gated check-in build pipeline.

Option to run CI builds

By default, CI builds are not run after the gated check-in process is complete and the changes are checked in.

However, if you do want CI builds to run after a gated check-in, select the Run CI triggers for committed changes check box. When you do this, the build pipeline does not add ***NO_CI*** to the changeset description. As a result, CI builds that are affected by the check-in are run.

A few other things to know

Build completion triggers

Build completion triggers are not yet supported in YAML syntax. After you create your YAML build pipeline, you can use the classic editor to specify a build completion trigger.

Wildcards

When specifying a branch or tag, you may use an exact name or a wildcard. Wildcards patterns allow * to match zero or more characters and ? to match a single character. For branches and tags, a wildcard may appear anywhere in the pattern.

For paths, you may include * as the final character, but it doesn't do anything differently from specifying the directory name by itself. You may not include * in the middle of a path filter, and you may not use ?.

trigger:
  branches:
    include:
    - master
    - releases/*
    - feature/*
    exclude:
    - releases/old*
    - feature/*-working
  paths:
    include:
    - '*' # same as '/' for the repository root
    exclude:
    - 'docs/*' # same as 'docs/'

Q & A

How do I protect my Git codebase from build breaks?

If your code is in a Git repo on Azure Repos or Team Foundation Server, you can create a branch policy that runs your build. See Improve code quality with branch policies. This option is also available for GitHub repos. See About protected branches.

My build didn't run. What happened?

Someone must view a page in your organization regularly for CI and scheduled builds to run. It can be any page, including, for example, Azure Pipelines.

Your organization goes dormant five minutes after the last user signed out of Azure DevOps. After that, each of your build pipelines will run one more time. For example, while your organization is dormant:

  • A nightly build of code in your organization will run only one night until someone signs in again.

  • CI builds of an Other Git repo will stop running until someone signs in again.

The YAML file in my branch is different than the YAML file in my master branch, which one is used?

  • For CI triggers, the YAML file that is in the branch you are pushing is evaluated to see if a CI build should be run.
  • For PR triggers, the YAML file that is in the source branch of the PR is evaluated to see if a PR build should be run.
  • For Scheduled triggers, the YAML file that is in the branch is used to set the scheduled triggers for that branch.

My CI or PR trigger doesn't seem to fire

Ensure that your CI or PR trigger isn't being overridden by the pipeline settings. For more information, see Overriding YAML triggers.

Do I need an agent?

You need at least one agent to run your build or release. Get an agent for Linux, macOS, or Windows.

I'm having problems. How can I troubleshoot them?

See Troubleshoot Build and Release.

I can't select a default agent pool and I can't queue my build or release. How do I fix this?

See Agent pools.

I use TFS on-premises and I don't see some of these features. Why not?

Some of these features are available only on Azure Pipelines and not yet available on-premises. Some features are available on-premises if you have upgraded to the latest version of TFS.