This is the second part of the blog series on how to move from Azure Pipelines to GitHub Actions.

This is a multi part article - find the other parts at the links below:

Trigger

Azure Pipelines

Trigger define when a pipeline starts. All triggers are event based and vary from a manual trigger, a push to repository and many more.
Azure DevOps set to have a couple of triggers:

  • manual trigger
  • changes to repository
  • timer trigger

It starts with the trigger key word:

1
2
3
4
5
6
7
8
9
10
11
12
13
trigger:
branches:
include:
- preview
- main
exclude:
- release*
paths:
include:
- terraform
exclude:
- .azuredevops
...

Timer trigger are configured with the schedule key word:

1
2
3
4
5
6
7
schedules:
- cron: "0 0 * * *"
displayName: Daily midnight build
branches:
include:
- main
...

Scheduled pipelines can still have a trigger based on commits, but if you do not need this or if you do not need a trigger at all, set the trigger as followed:

1
2
trigger: none
...

GitHub Actions

GitHub Actions on the other hand, can be triggered in several ways.

  • manual trigger
  • changes to repository
  • timer trigger
  • Issues
  • Labels
  • project items
  • many more
    • find the full list here

Everything starts with the on key word:

1
2
3
4
5
6
7
8
9
10
11
12
name: build and deploy

on:
push:
branches:
- main
- preview
pull_request:
- main
- preview
workflow_dispatch:
...

By default, Azure Pipelines can be triggered manually from the portal, GitHub Actions must have a certain trigger - workflow_dispatch.

Runtime Parameters

Adding parameters at runtime can be great to make quick modifications for an manual triggered pipeline. For instance, you could choose the agent operating system.

Azure Pipelines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
trigger: none

parameters:
- name: VM
displayName: VM Agent Operating System
default: ubuntu-latest
values:
- ubuntu-latest
- windows-latest


stages:
- stage: build
pool:
vmImage: ${{ parameters.VM }}
jobs:
- job: build
steps:
- script: echo Hello, world!
displayName: 'Run a one-line script'

- script: |
echo Add other tasks to build, test, and deploy your project.
echo See https://aka.ms/yaml
displayName: 'Run a multi-line script'

Azure Pipeline ParametersAzure Pipeline Parameters

You can reference parameters as followed:

1
2
3
vmImage: ${{ parameters.<parameterName> }}

vmImage: ${{ parameters.VM }}

You can learn more about runtime parameters here.

GitHub Actions

In GitHub Actions, runtime parameters are part of the trigger workflow_dispatch. We can add inputs to the trigger and reference them later in the pipeline.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
name: build and deploy

on:
workflow_dispatch:
inputs:
runner_os:
description: 'operating sysyem of the runner'
required: true
default: 'ubuntu-20.04'
type: choice
options:
- ubuntu-20.04
- windows-2019

jobs:
build:
runs-on: ${{ github.event.inputs.runner_os }}

steps:
- name: Run a one-line script
run: echo Hello, world!

GitHub Actions workflow_dispatch inputGitHub Actions workflow_dispatch input

You can reference workflow_dispatch input as followed:

1
2
3
runs-on: ${{ github.event.inputs.<input name> }}

runs-on: ${{ github.event.inputs.runner_os }}

You can learn more about workflow_dispatch input here.

Concurrency / Dependencies / Conditions

By default, Azure Pipelines Stages and jobs are executed one after the other. You can create dependencies or even start them at the same time.
GitHub Actions executes jobs by default in parallel.
Therefore, the approach is entirely different, but its quickly configured.

Azure Pipelines

Dependencies are created using the dependsOn key word within stages or jobs. Conditions are added with the condition key word.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
- stage: Build
jobs:
- job: build
displayName: build the application
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: self
# tasks
- stage: Deploy
dependsOn: Build
condition: succeeded()
jobs:
- job: deploy
displayName: deploy the application
pool:
vmImage: 'ubuntu-latest'
steps:

- checkout: self
# tasks

Now, the stage Deploy depends on the stage Build and is has to ran successfully, if it fails, Deploy will not run. The same conditions and dependsOn settings can be applied to jobs.
If you want to start two stages or jobs at the same time, add the following dependsOn statement: dependsOn: []

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- stage: Build_Windows
dependsOn: []
jobs:
- job: build
displayName: build the application
pool:
vmImage: 'windows-latest'
steps:
- checkout: self
# tasks
- stage: Build_Linux
dependsOn: []
jobs:
- job: build
displayName: build the application
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: self
# tasks
- stage: Deploy
dependsOn:
- Build_Windows
- Build_Linux
condition: succeeded()
jobs:
- job: deploy
displayName: deploy the application
pool:
vmImage: 'ubuntu-latest'
steps:

- checkout: self
# tasks

Now, Build_Windows and Build_Linux start at the same time and Deploy will wait until both are ready and ran successful.
You can find the full list of conditions here.

GitHub Actions

As mentioned above, GitHub Actions behaves totally different than Azure Pipelines. Concurrency is built-in the default.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
...

Both jobs would executed simultaneously. To create a dependency, the needs key word is required.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
deploy:
needs: build
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
...

To create a condition, a simple if-statement can be added. By default when you use the needs key word, the job that depends on the previous one has to run successfully in order to be executed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
deploy:
needs: build
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
...

Create multiple dependencies, you can use the following snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
jobs:
build_windows:
runs-on: windows-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
build_linux:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
deploy:
needs: [build_windows, build_linux]
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install

Agents / Runner

Agents or Runners are the machines, the pipeline will be executed on. Both Azure Pipelines and GitHub Action have cloud hosted, publicly available agents with several different operating systems:

  • Windows
  • Linux
  • MacOS

Cloud Agents

Each agent has software preinstalled so you don’t have to worry about it. However, sometimes it is necessary to install a specific version or to install tools you require yourself.
The table below contains links to the agents and how they are set up.

Azure Pipelines GitHub Actions
Available Worker Link Link
Installed Software find the link in the included Software row of the link above Link

Self Hosted

You can also host your own agents either on a virtual machine or as container if you have privacy requirements or need more performance.

It is important to notice, that Azure DevOps charges 15$ per month per self-hosted agent and GitHub does not apply any charges.

Azure Pipelines

Kind of Agent Docs
Self-hosted Windows agents Link
Self-hosted macOS agents Link
Self-hosted Linux agents Link
Self-hosted agent in Docker Link

In Azure Pipelines, the agent can be configured in two places, either on the stage or the job. The job can inherit the configuration from the stage.
It is defined by the pool key word

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- stage: Build
pool:
vmImage: 'ubuntu-latest'
jobs:
- job: build
displayName: build app
steps:
- task: 'Npm@1'
inputs:
command: 'install'
- powershell: |
Write-Host $([DateTime]::Now)
displayName: 'Generate...'
errorActionPreference: 'continue'

The job can also have their own pool configured:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- stage: Build
jobs:
- job: build
displayName: build app
pool:
vmImage: 'ubuntu-latest'
steps:
- task: 'Npm@1'
inputs:
command: 'install'
- powershell: |
Write-Host $([DateTime]::Now)
displayName: 'Generate...'
errorActionPreference: 'continue'

GitHub Actions

GitHub Actions define their runners per job using the runs-on key word:

1
2
3
4
5
6
7
8
9
10
11
...
jobs:
build_deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: npm install
run: npm install
...

Self-Hosted runners can be configured per organization within the settings:

GitHub Actions - Add Self hosted RunnerGitHub Actions - Add Self hosted Runner

GitHub Actions - Add Self hosted RunnerGitHub Actions - Add Self hosted Runner

Select the operating system you want to deploy to and follow the instructions below.

Next

In part 3 we will check out deployments, variables, secrets, and more!