Справочник для gitflic-ci.yaml
файла
В этой документации перечислены ключевые слова для конфигурации вашего gitflic-ci.yaml
файла
Ключевые слова
Ключевые слова | Глобальные | Для задачи | Описание |
---|---|---|---|
stages |
+ | Имена и порядок выполнения этапов конвейера | |
image |
+ | + | Образ Docker |
cache |
+ | + | Список файлов и каталогов для кэширования между задачами |
include |
+ | + | Включение в конфигурацию внешних .yaml файлов |
variables |
+ | + | Список переменных, объявленных дополнительно |
stage |
+ | Определение этапа для задачи | |
before_script |
+ | + | Список shell-скриптов, которые будут выполнены агентом перед задачей |
scripts |
+ | Список shell-скриптов, которые будут выполнены агентом | |
after_script |
+ | + | Список shell-скриптов, которые будут выполнены агентом после задачи |
artifacts |
+ | Список файлов и каталогов, которые будут прикреплены к задаче в случае успеха | |
needs |
+ | Массив названий задач, успешное выполнение которых необходимо для запуска текущей задачи | |
when |
+ | Определение условий запуска для задач | |
rules |
+ | Список условий, с помощью которых можно влиять на поведение полей | |
variables |
+ | + | Переменные для задач, список предопределенных переменных, доступных для использования |
except |
+ | Название веток, для которых не будет создана задача | |
only |
+ | Название веток, для которых будет создана задача | |
tags |
+ | Теги задачи для агента | |
allow_failure |
+ | Правило, позволяющее продолжить работу конвейера в случае сбоя задачи | |
trigger |
+ | Правило, позволяющее запустить выполнение одного конвейера из другого | |
extends |
+ | Правило, позволяющее наследовать конфигурации задач от других задач или шаблонов |
stages
Тип ключевого слова: Глобальное ключевое слово.
Используйте stages
, чтобы определить список этапов выполнения конвейера.
Если этапы не определены в gitflic-ci.yaml
файле, то по умолчанию имеются следующие предопределенные этапы:
- .pre
- build
- test
- deploy
- .post
Порядок элементов этапов определяет порядок выполнения задач:
- Задачи на одном этапе выполняются параллельно.
- Задачи на следующем этапе запускаются после успешного завершения задач на предыдущем этапе.
- Если конвейер содержит только задачи на этапах .pre или .post, он не запускается. На другом этапе должна быть хотя бы одна другая работа. .pre и .post этапы можно использовать в требуемой конфигурации конвейера для определения задач соответствия, которые должны выполняться до или после задач конвейера проекта.
Пример:
stages:
- build
- test
- deploy
- Все этапы выполняются друг за другом. Если какой-либо этап будет провален, то не начнется следующий и конвейер завершится с ошибкой.
- Если все эти этапы будут успешно пройдены, то конвейер будет считаться успешно выполненным.
include
Тип ключевого слова: Глобальное ключевое слово.
Вы можете использовать include
для включения дополнительных файлов yaml.
include: - local
Используйте include: - local
для подключения файлов, находящихся в репозитории локально.
Пример:
- local:
- "gitflic-1.yaml"
- "gitflic-2.yaml"
include:remote
Используйте include: - remote
для подключения файлов, находящихся в удаленных репозиториях.
Функционал доступен в Self-Hosted версии сервиса
Пример:
- remote:
- "https://external/link/file1.yaml"
- "https://external/link/file2.yml"
include:project
Используйте include: - project
для подключения файлов, находящихся в других репозиториях.
Пример:
include:
- project:
project_path: 'my-group/my-project'
ref: v1.0.0
file:
- 'gitflic-ci.yml'
image
Тип ключевого слова: Глобальное ключевое слово. Может использоваться как ключевое слово для задачи.
Используйте image
, чтобы указать образ Docker, в котором выполняется конвейер.
Пример:
image: maven:3.8.5-openjdk-11-slim
Пример:
job:
stage: build
image: maven:3.8.5-openjdk-11-slim
cache
Тип ключевого слова: Глобальное ключевое слово. Может использоваться как ключевое слово для задачи.
Используйте cache
, чтобы указать список файлов и каталогов для кэширования между задачами. Вы можете использовать только те пути, которые есть в локальной рабочей копии.
Кэширование распределяется между конвейерами и заданиями. Кэши восстанавливаются раньше артефактов.
cache:[]
Используйте cache:[]
для отключения кэша для определенной задачи.
cache:paths
Используйте cache:paths
, чтобы выбрать файлы или каталоги для кэширования.
Пример:
cache:
paths:
- .m2/repository/
- core/target/
- desktop/target/
cache:key
Используйте cache:key
, чтобы присвоить кэшу уникальный идентификационный ключ. Все задачи, использующие один и тот же ключ кэша, используют один и тот же кэш.
Если не задано, по умолчанию используется ключ default
. Все задания с cache ключевым словом, но без cache:key совместного использования default
кэша.
Должен использоваться с cache:paths
, иначе ничего не кэшируется.
Пример:
cache:
keys:
- test
paths:
- desktop/target/
variables
Тип ключевого слова: Глобальное ключевое слово. Может использоваться как ключевое слово для задачи.
Используйте variables
чтобы объявить дополнительные CI/CD переменные для данной задачи.
Возможные значения
- Имя переменной может содержать только цифры, латинские буквы и нижние подчеркивания (
_
). - Значение переменной должно быть строкой (обернуто в одинарные
'
или двойные"
кавычки).
Пример:
job:
scripts:
- echo "this job has no additional variables"
job_with_variables:
variables:
VAR: "/variable"
scripts:
- echo $VAR
Примечания
- Переменные, определенные в YAML файле являются публично видимыми, в них небезопасно определять чувствительную информацию. Объявляйте переменные, значения которых не должны быть публичны, через вкладку CI/CD в настройках проекта.
stage
Используйте stage
, для определения этапа для задачи.
Тип ключевого слова: Ключевое слово для задачи.
Пример:
stages:
- build
- deploy
job:
stage: build
scripts
Используйте scripts
, для указания команд, которые должны выполняться агентом.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения: Массив строк.
job1:
scripts: apt-get update
job2:
scripts:
- apt-get -y install maven
- apt-get -y install git
before_script
Используйте before_script
для указания команд, которые должны выполняться перед основными командами каждой задачи после восстановления артефактов.
При использовании before_script
в качестве глобального ключевого слова, команды будут выполняться перед каждой задачей.
Тип ключевого слова: Ключевое слово для задачи. Может использоваться как глобальное ключевое слово.
Возможные значения: Массив строк.
Пример:
job1:
scripts: apt-get update
before_script:
- apt-get -y install maven
- apt-get -y install git
after_script
Используйте after_script
для указания команд, которые должны выполняться после основных команд каждой успешной задачи.
При использовании after_script
в качестве глобального ключевого слова, команды будут выполняться после каждой задачи.
Тип ключевого слова: Ключевое слово для задачи. Может использоваться как глобальное ключевое слово.
Возможные значения: Массив строк.
Пример:
job1:
scripts: apt-get update
after_script:
- apt-get update
- apt-get -y install maven
- apt-get -y install git
Дополнительные сведения:
Если время ожидания задачи истекло или она была отменёна, команды after_script
не выполняются.
artifacts
Используйте артефакты, чтобы указать, какие файлы сохранять в качестве артефактов задачи. Артефакты задачи - это список файлов и каталогов, которые присоединяются к задаче при её выполнении.
По умолчанию, задачи автоматически загружают все артефакты, созданные предыдущими задачами в рамках одного этапа.
При использовании ключевого слова needs
, задачи могут загружать артефакты только из задач, определённых в конфигурации needs
.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения: Массив путей к файлам относительно каталога проекта.
artifacts:paths
Пути относятся к каталогу проекта и не могут напрямую ссылаться за его пределы.
Пример:
artifacts:
paths:
- bin/usr/
- bin/path
- frontend/saw
artifacts:name
Используйте artifacts:name
для задания имени артефакта, создаваемого в результате выполнения задания.
Пример:
artifacts:
name: job_artifacts
paths:
- bin/usr/
- bin/path
- frontend/saw
artifacts:reports
Используйте artifacts:reports
для загрузки SAST/DAST отчетов и отчетов junit.
- Результаты junit-отчетов тестов отображаются на вкладке задачи
Тесты
.
Тип ключевого слова: Ключевое слово для задачи. Вы можете использовать его только как часть задачи.
Возможные значения: Массив путей к файлам относительно каталога проекта.
Пример:
artifacts:
reports:
sast:
paths:
- sast_report.json
dast:
paths:
- dast_report.json
- dast_report_2.json
junit:
paths:
- target/surefire-reports/*
needs
Используйте needs
, чтобы указать зависимости между задачами в конвейере. Ключевое слово needs
позволяет явно определить порядок выполнения задач.
Задачи могут загружать артефакты только из задач, определенных в needs
. Задачи на более поздних этапах автоматически загружают все артефакты, созданные на более ранних этапах, если они указаны в needs
. При указании массива задач, задача будет выполняться только после успешного выполнения всех указанных задач.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения: Массив путей к файлам относительно каталога проекта.
Пример:
stages:
- build
- test
build_job:
stage: build
script:
- echo "Building..."
test_job:
stage: test
script:
- echo "Testing..."
needs: [ build_job ]
when
Используйте when
для настройки условий запуска заданий. Если в задании не определено, значение по умолчанию — when: on_success
.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения:
on_success
(значение по умолчанию): задача будет запускаться только в том случае, если ни одно задание на более ранних этапах не завершилось сбоем или не имеетallow_failure: true
manual
: задача будет выполняться только при ручном запуске.
Пример:
stages:
- build
- test
- deploy
build_job:
stage: build
script:
- echo "Building the project..."
test_job:
stage: test
script:
- echo "Running tests..."
when: on_success
deploy_job:
stage: deploy
script:
- echo "Deploying the project..."
when: manual
only:
- main
rules
Тип ключевого слова: Ключевое слово для задачи.
Используйте rules
, чтобы управлять созданием задач и изменять значения их полей на основе логических выражений.
rules
вычисляются при создании конвейера. Вычисление происходит последовательно, останавливается на первом истинном правиле. Когда истинное правило найдено, задача или включается в конвейер, или исключается из него, также происходит изменение атрибутов задачи в соответствии с данным правилом.
rules
являются альтернативой ключевым словам only/except
и не могут быть использованы вместе с ними. Если у задачи указаны как rules
, так и only
и/или except
, то обработка конвейера завершится с ошибкой.
rules
представляют собой массив правил, каждое из которых состоит из произвольного набора следующих ключевых слов:
Правило из rules
является истинным, если поле if
или отсутствует, или представляет собой истинное логическое выражение.
Задача будет создана, если:
rules
не объявлены или представляют собой пустой массив.- Первое по порядку истинное правило имеет
when
неnever
.
Задача не будет создана, если:
- Ни одно из правил в
rules
не является истинным. - Первое по порядку истинное правило имеет
when: never
.
rules:if
Используйте rules:if
, чтобы определять, при каких условиях правило будет истинно.
Возможные значения
- Выражение с CI/CD переменными, а именно:
Сравнение переменной со строкой
Вы можете использовать операторы равенства ==
и !=
для сравнения переменной со строкой. Допустимы как одинарные '
, так и двойные "
кавычки. Порядок операндов не имеет значения, поэтому переменная может быть первой, или строка может быть первой. Например:
if: $VAR == "string"
if: $VAR != "string"
if: "string" == $VAR
Сравнение двух переменных
Вы можете сравнивать между собой значения двух переменных. Например:
if: $VAR1 == $VAR2
if: $VAR1 != $VAR2
Проверка переменной на существование
Вы можете сравнивать значение переменной с null
:
if: $VAR == null
if: $VAR != null
Вы можете сравнивать значение переменной с пустой строкой:
if: $VAR == ""
if: $VAR != ""
Вы можете проверять переменную на существование:
if: $VAR
Данное выражение будет истинно только в том случае, если переменная определена и её значение - не пустая строка.
Сравнение переменной с regex pattern
Вы можете выполнять сопоставление регулярного выражений со значением переменной с помощью операторов = ~ и !~. Для регулярных выражений используется синтаксис RE2. Регулярное выражение должно быть обернуто в символы косой черты /
.
Сопоставление является истинным, если:
- Оператор
=~
: найдена хотя бы одна подстрока, полностью удовлетворяющая регулярному выражению. - Оператор
!~
: не найдено ни одной подстроки, полностью удовлетворяющей регулярному выражению.
Примеры:
if: $VAR =~ /^feature/
if: $VAR !~/^feature/
Первое выражение будет истинным для значения переменной: "feature/rules/if"
и ложен для "base/feature"
. Второе выражение для первого значения будет ложным, а для второго - истинным.
Примечание: односимвольные регулярные выражения (такие, как /./
) не поддерживаются и вызывают ошибку.
В качестве правого операнда может выступать другая переменная, её значение будет интерпретировано как регулярное выражение. Например:
if: $VAR =~ $REGEX_VAR
if: $VAR !~ $REGEX_VAR
Примечание: если значение переменной не обернуто в /
, оно будет интерпретировано как обернутое (например, для REGEX_VAR: "^feature"
результат будет аналогичен REGEX_VAR: "/^feature/"
).
Комбинация атомарных выражений
Два выражения могут быть соединены с помощью логических связок:
$VAR1 =~ /^feature/ && $VAR2 == "two"
$VAR1 || $VAR2 != "three" && $VAR3 =~ /main$/
$VAR1 AND $VAR2
$VAR1 OR $VAR2
Выражения можно группировать с помощью (
и )
:
$VAR1 && ($VAR2 == "something" || $VAR3 == "something else")
Логические связки и (
)
имеют следующий приоритет выполнения:
- Выражение в скобках.
- Конъюнкция выражений -
&&
илиAND
. - Дизъюнкция выражений -
||
илиOR
.
Пример:
job:
scripts: echo "This job uses rules!"
variables:
VAR1: "one"
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
when: never
- if: $CI_COMMIT_REF_NAME =~ /^feature/ && VAR1 == "one"
allow_failure: true
variables:
VAR1: "one from rule"
VAR2: "two from rule"
- if: $CI_COMMIT_TAG
- when: manual
Для данной задачи определены четыре правила:
- Первое правило будет истинно, если конвейер создается на стандартной ветке для проекта (например
main
илиmaster
). - Второе правило будет истинно если конвейер создается на ветке, название которой начинается с
feature
и внутри переменнойVAR1
лежит строкаone
. - Третье правило будет истинно если переменная
CI_COMMIT_TAG
объявлена. - Четвертое правило всегда истинно.
Если первое правило оказалось истинным, задача не будет создана, так как when: never
.
Если второе правило оказалось истинным, а первое ложным, то задача будет создана. Поле allow_failure
для задачи станет true
, переменная VAR1
будет перезаписана, переменная VAR2
будет добавлена к задаче, значение поля when
задачи изменено не будет.
Если третье правило оказалось истинным, а предыдущие ложными, то задача будет создана, при этом её поля не будут изменены.
Если ни одно из предыдущих правил не оказалось истинным, четвертое правило поменяет значение поля when
задачи на manual
.
CI/CD переменные
Использование правил неразрывно связано с CI/CD переменными. На данный момент в конфигурации конвейера (и его задач) можно использовать переменные из следующих источников:
- Объявленные через UI в настройках CI/CD для проекта. Такие переменные можно маскировать, не давая отображать их значения в логах, что повышает безопасность.
- Предопределенные переменные.
- Глобальные переменные, объявленные в поле
variables
для конвейера. Такие переменные доступны всем задачам данного конвейера. - Переменные, объявленные в поле
variables
для задачи. Такие переменные доступны только той задаче, внутри которой они объявлены.
Примечания:
- Если переменная с одним и тем же именем объявлена в разных местах, значение будет перезаписано в соответствии с приоритетом перезаписи источников CI/CD переменных.
Предопределенные CI/CD переменные
Имя переменной | Описание |
---|---|
CI_PROJECT_URL |
URL проекта, для которого создан конвейер (например https://gitflic.ru/project/someuser/some-project-name ). |
CI_PROJECT_TITLE |
Название проекта, отображающееся в UI (например Some Project Name ). |
CI_PROJECT_NAME |
Название директории проекта (например some-project-name ). |
CI_PROJECT_VISIBILITY |
Строка private или public , в зависимости от публичности проекта. |
CI_DEFAULT_BRANCH |
Стандартная ветка для проекта (например master ). |
GITFLIC_USER_EMAIL |
Email инициатора запуска конвейера. |
GITFLIC_USER_LOGIN |
Имя пользователя инициатора запуска конвейера. |
CI_COMMIT_REF_NAME |
Название ветки или тега, на которых запускается конвейер (например feature/rules ). |
CI_COMMIT_SHA |
Полный хэш коммита, на котором запускается конвейер. |
CI_COMMIT_TAG |
Название тега, на котором запускается конвейер. Возвращает пустую строку, если конвейер запущен не по тегу. |
CI_COMMIT_MESSAGE |
Сообщение коммита. |
CI_PIPELINE_ID |
UUID конвейера. |
CI_PIPELINE_IID |
Локальный для проекта ID конвейера, уникален на уровне проекта. |
CI_PIPELINE_SOURCE |
Указание источника, который инициировал текущий конвейер. |
CI_REGISTRY |
Адрес сервера реестра контейнеров, в формате <host>[:<port>] (например: registry.gitflic.ru) |
CI_REGISTRY_IMAGE |
Базовый адрес реестра контейнеров, в формате <host>[:<port>]/project/<полный путь к проекту> (например: registry.gitflic.ru/project/my_company/my_project) |
CI_REGISTRY_PASSWORD |
Пароль для авторизации в реестре контейнеров |
CI_REGISTRY_USER |
Имя пользователя для авторизации в реестре контейнеров |
CI_PIPELINE_SOURCE
Возможные значения переменной CI_PIPELINE_SOURCE
:
- push: Конвейер был запущен после отправки кода в репозиторий.
- trigger: Конвейер был запущен с использованием ключевого слова
trigger
. - schedule: Конвейер был запущен по расписанию.
- web: Конвейер был запущен вручную через веб-интерфейс.
- api: Конвейер был запущен через API.
- parent_pipeline: Конвейер был запущен другим конвейером.
- merge_request_event: Конвейер был запущен по событию, связанному с запросом на слияние.
Порядок перезаписи CI/CD переменных
Значение приоритета перезаписи для различных источников переменных следующий (от наибольшего к наименьшему):
- Переменные, объявленные для проекта через UI.
- Переменные, объявленные для задачи в конфиг файле.
- Глобальные переменные, объявленные для конвейера в конфиг файле.
- Предопределенные переменные.
Переменные с равным приоритетом перезаписывают друг друга.
Пример
- Для проекта через UI объявлена маскированная переменная
POPULAR_VAR
со значениемPopular from project
. - В поле
variables
для конвейера объявлена переменная с таким же именем, но другим значением:POPULAR_VAR: "Popular from pipeline"
, а также переменнаяOBSCURE_VAR: "Obscure from pipeline"
. - В поле
variables
для задачиjob 0
объявлены обе эти переменные, со следующими значениями:POPULAR_VAR: "Popular from job 0"
,OBSCURE_VAR: "Obscure from job 0"
. - В конечном итоге получим, что для задачи
job 0
значения вышеописанных переменных будут следующими:POPULAR_VAR
будет равнаPopular from project
и замаскирована, аOBSCURE_VAR
будет равнаObscure from job 0
. - Получим, что для переменной
POPULAR_VAR
ни значение из задачи, ни значение из конвейера не перезаписало значение, объявленное через UI для проекта. При этом значение переменной, объявленной в конвейере (OBSCURE_VAR
), для задачиjob 0
было перезаписано.
rules:allow_failure
При истинности правила, если это поле определено, перезаписывает значение поля allow_failure
задачи.
rules:variables
При истинности правила, если это поле определено, добавляет переменные в задачу, потенциально перезаписывая уже объявленные.
Возможные значения: Набор полей формата VARIABLE_NAME: "variable value"
.
Пример:
job:
variables:
ARGUMENT: "default"
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
variables: # Перезаписываем значение
ARGUMENT: "important" # существующей переменной
- if: $CI_COMMIT_REF_NAME =~ /feature/
variables:
IS_A_FEATURE: "true" # Определяем новую переменную
scripts:
- echo "Run script with $ARGUMENT as an argument"
- echo "Run another script if $IS_A_FEATURE exists"
Имя переменной | Значение | Результат |
---|---|---|
GIT_STRATEGY |
none |
Отключение клонирования репозитория |
GIT_STRATEGY |
Любое, кроме none |
Применяется git fetch |
ARTIFACT_DOWNLOAD_STRATEGY |
none |
Отключение скачивания артефакта |
rules:when
При истинности правила, если это поле определено, перезаписывает значение поля when
задачи.
Возможные значения
never
- задача не будет добавлена в конвейерmanual
- задача выполняется только при ручном запуске из UI.on_success
- задача выполняется, только если все задачи сallow_failure: false
выполнились успешно.
tags
Используйте tags
для настройки агента.
Вы можете указать теги для определенного агента в его настройках.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения: Массив названий тегов.
Пример:
job:
tags:
- test
- build
allow_failure
Используйте allow_failure
, чтобы определить, должен ли конвейер продолжать работу в случае сбоя задания.
-
Чтобы конвейер продолжал выполнять последующие задачи, используйте
allow_failure: true
. -
Чтобы запретить конвейеру выполнение последующих задачи, используйте
allow_failure: false
.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения:
true
false
(значение по умолчанию)
Для
manual
задач, выполняющихся только при ручном запуске из UI, по умолчанию значениеtrue
except
Используйте except
чтобы указать ветки на которых задача не будет создана.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения: Массив названий веток.
Пример:
job:
except:
- master
- deploy
only
Используйте only
чтобы указать ветки на которых будет создана задача.
Тип ключевого слова: Ключевое слово для задачи.
Возможные значения: Массив названий веток.
Пример:
job:
only:
- master
trigger
Используйте trigger
для настройки вызова одного конвейера из другого.
Для корректной работы триггеров в рамках нескольких проектов, у пользователя, запускающего конвейер, должна быть роль не ниже роли разработчик
в дочернем проекте.
Тип ключевого слова: Ключевое слово для задачи.
trigger:project
- Это поле указывает на проект, в котором запускается конвейер.
trigger:branch
- Это поле указывает на ветку, конвейер для которой запуститься в проекте указанном в поле trigger:project
.
trigger:strategy
- Это поле указывает на связь между задачей и дочерним конвейером. Если ключевое слово отсутствует, то задача-триггер завершается сразу после создания дочернего конвейера, не дожидаясь его успешного выполнения.
Возможное значение:
depend
: Для успешного завершения задачи требуется успешное завершение дочернего конвейера.
trigger:forward
- Это поле указывает, какие артефакты, переменные и/или другие данные будут передаваться в другой проект при запуске триггера.
Возможные значения:
yaml_variables
:true
(по умолчанию), илиfalse
. При значенииtrue
, переменные, определенные в конвейере, содержащем триггер, передаются в дочерние конвейеры.pipeline_variables
:true
илиfalse
(по умолчанию). При значенииtrue
, переменные, определенные в UI проекта, содержащем триггер, передаются в дочерние конвейеры.
Могут использоваться также ключевые слова для задач: trigger:include
, trigger:rules
.
Пример:
trigger-project:
trigger:
project: adminuser/cicd-parent
strategy: depend
forward:
yaml_variables: true
pipeline_variables: true
trigger-child:
trigger:
include:
- local:
- "gitflic-1.yaml"
strategy: depend
forward:
yaml_variables: true
pipeline_variables: true
extends
Используйте extends
для наследования конфигурации задач от других задач или от шаблонов. При наличии одинаковых ключевых слов в шаблоне/задаче и основной задачах, использоваться будут ключевые слова из основной задачи.
Шаблон - задача, название которой начинается с .
. Шаблонные задачи не отображаются в конвейере, и не исполняются отдельно от основной задачи.
Тип ключевого слова: Ключевое слово для задачи.
Для основной задачи необходимо указать ключевое слово stage
, иначе задача будет отображаться в этапе по умолчанию test
.
Пример:
.default_template:
before_script:
- echo "Executing before_script"
script:
- echo "Executing script"
build_job:
stage: build
extends: .default_template
script:
- echo "Building the project"
- make build