Skip to main content

Writing workflows

Writing your first GitHub Actions workflow

Workflows are defined using YAML syntax (https://yaml.org/). Workflow files must have either a .yml or .yaml extension and they are save to .github/workflows directory in your repository. One way to create workflows is to navigate to your GitHub repository and open the Actions tab. There you can select pre-defined workflows or create your own by clicking 'set up a workflow' yourself as shown in the following image:

Github workflow creation

TASK: Create the first workflow

Create a new repository to Github and enable "Add a README file" to create README.md file to your repository Then, follow the instructions in https://docs.github.com/en/actions/writing-workflows/quickstart#creating-your-first-workflow to create and run your first Github actions workflow.

Here's an example of a workflow file similar to the one you have created in the task. Let's break down its structure to understand how it works:

name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."

The name defines The name of the workflow.

The on defines the event or events that triggers the workflow (e.g., push, pull_request, schedule). You can define multiple events that triggers the workflow in the following way [push, pull_request]. Read more about events that trigger workflow in Github docs.

You can also limit the trigger to specific branches:

on:
push:
branches:
- main

In this example, the workflow is configured to trigger whenever a push is made to the main branch of the repository. You can also use inline bracket list as shown in the following example.

on:
push:
branches: [main, develop]

The jobs section specifies a set of tasks that the workflow will execute. In this example there is one job that is named Explore-GitHub-Actions.

The runs-on defines that job runs on an ubuntu-latest virtual machine. You can also specify the ubuntu version for example, runs-on: ubuntu-22.04. Read more about choosing the runner for a job in Github docs.

The steps defines the individual tasks within a job. The run keyword is used to define a shell command or script that will be executed in a workflow step. Each run step executes a command directly on the runner (the virtual machine or container where the job is running).

note

Steps run sequentially, in order. Each step waits for the previous one to finish before starting.

There are also multiline commands in steps such as:

- name: List files in the repository
run: |
ls ${{ github.workspace }}

This lists all files in the repository directory on the runner using the ls command. The ${{ ... }} syntax is used to access GitHub context variables. The ${{ github.workspace }} returns absolute path to the GitHub workspace directory on the runner. Read more in accessing contextual information

The | symbol in the run section of a GitHub Actions workflow is a YAML syntax feature *block scalar. It is used to write multi-line strings or commands in a more readable format. You can write multiple shell commands under one run block, for example:

- name: List files in the repository
run: |
echo "Listing files:"
ls ${{ github.workspace }}
echo "Done"

Multiple jobs

By default, when your workflow contains multiple jobs, they run in parallel. In the example below, there are three jobs: build, test, and deploy.

The deploy job uses the needs keyword to specify that it depends on the successful completion of both the build and test jobs. This means deploy will only start after both of those jobs have finished successfully, ensuring that deployment happens only if the build and tests pass.

name: Workflow with Dependencies

on: [push]

jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building..."

test:
runs-on: ubuntu-latest
steps:
- run: echo "Testing..."

deploy:
needs: [build, test]
runs-on: ubuntu-latest
steps:
- run: echo "Deploying app only after build and test succeed"

You can read more about needs syntax here.

GitHub has limits on the number of jobs that can run concurrently, which may vary based on your account type. Refer to the GitHub documentation for the details on these limitations.

Scheduling workflows

You can schedule GitHub workflows using the schedule event, which uses cron syntax to define when the workflow should run automatically.

The following example executes the workflow every Monday at 7:30 AM.

on:
schedule:
- cron: '30 7 * * 1'

You can add multiple schedules by listing more cron entries.

Multiple workflows

If you have multiple workflow YAML files in your repository, GitHub Actions will trigger and run them independently and in parallel when their respective on conditions are met. Each workflow runs in its own environment and does not wait for other workflows to finish unless you explicitly coordinate them.

To coordinate workflows, you can use workflow_run event to trigger one workflow after another completes. For example, you can configure a workflow to run only after another workflow has finished successfully.

on:
workflow_run:
workflows: ["Build"]
types:
- completed

Next, we start to implement our first CI pipeline using Github Actions.

Further reading