GitLab CI Events
This page contains information related to upcoming products, features, and functionality.
It is important to note that the information presented is for informational purposes only.
Please do not rely on this information for purchasing or planning purposes.
The development, release, and timing of any products, features, or functionality may be
subject to change or delay and remain at the sole discretion of GitLab Inc.
Summary
In order to unlock innovation and build more value, GitLab is expected to be
the center of automation related to DevSecOps processes. We want to transform
GitLab into a programming environment, that will make it possible for engineers
to model various workflows on top of CI/CD pipelines. Today, users must create
custom automation around webhooks or scheduled pipelines to build required
workflows.
In order to make this automation easier for our users, we want to build a
powerful CI/CD eventing system, that will make it possible to run pipelines
whenever something happens inside or outside of GitLab.
A typical use-case is to run a CI/CD job whenever someone creates an issue,
posts a comment, changes a merge request status from “draft” to “ready for
review” or adds a new member to a group.
To build that new technology, we should:
- Emit many hierarchical events from within GitLab in a more advanced way than we do it today.
- Make it affordable to run this automation, that will react to GitLab events, at scale.
- Provide a set of conventions and libraries to make writing the automation easier.
Goals
While “GitLab Events Platform”
aims to build new abstractions around emitting events in GitLab, “GitLab CI
Events” blueprint is about making it possible to:
- Define a way in which users will configure when an event emitted will result in a CI pipeline being run.
- Describe technology required to match subscriptions with events at GitLab.com scale and beyond.
- Describe technology we could use to reduce the cost of running automation jobs significantly.
Proposal
Decisions
Requirements
Any accepted proposal should take in consideration the following requirements and characteristics:
- Defining events should be done in separate files.
- If we define all events in a single file, then the single file gets too complicated and hard to
maintain for users. Then, users need to separate their configs with the
include
keyword again and we end up
with the same solution.
- The structure of the pipelines, the personas and the jobs will be different depending on the events being
subscribed to and the goals of the subscription.
- A single subscription configuration file should define a single pipeline that is created when an event is triggered.
- The pipeline config can include other files with the
include
keyword.
- The pipeline can have many jobs and trigger child pipelines or multi-project pipelines.
- The events and handling syntax should use the existing CI config syntax where it is pragmatic to do so.
- It’ll be easier for users to adapt. It’ll require less work to implement.
- The event subscription and emiting events should be performant, scalable, and non blocking.
- Reading from the database is usually faster than reading from files.
- A CI event can potentially have many subscriptions.
This also includes evaluating the right YAML files to create pipelines.
- The main business logic (e.g. creating an issue) should not be affected
by any subscriptions to the given CI event (e.g. issue created).
- The CI events design should be implemented in a maintainable and extensible way.
- If there is a
issues/create
event, then any new event (merge_request/created
) can be added without
much effort.
- We expect that many events will be added. It should be trivial for developers to
register domain events (e.g. ‘issue closed’) as GitLab-defined CI events.
- Also, we should consider the opportunity of supporting user-defined CI events long term (e.g. ‘order shipped’).
Options
For now, we have technical 5 proposals;
- Proposal 1: Using the
.gitlab-ci.yml
file
Based on;
- Proposal 2: Using the
rules
keyword
Highly inefficient way.
- Proposal 3: Using the
.gitlab/ci/events
folder
Involves file reading for every event.
- Proposal 4: Creating events via a CI config file
Separate configuration files for defininig events.
- Proposal 5: Combined proposal
Combination of all of the proposals listed above.
Context
We did some brainstorming in an issue
with multiple use-cases for running CI pipelines based on subscriptions to CI
events. The pattern of using hierarchical events emerged, it is clear that
events may be grouped together by type or by origin.
For example:
annotate:
on: issue/created
script: ./annotate $[[ event.issue.id ]]
summarize:
on: issue/closed
script: ./summarize $[[ event.issue.id ]]
When making this decision we didn’t focus on the syntax yet, but the grouping
of events seems to be useful in majority of use-cases.
Currently, we have two proof-of-concept (POC) implementations:
They both have similar ideas;
-
Find a new CI Config syntax to define pipeline events.
Example 1:
workflow:
events:
- events/package/published
# or
workflow:
on:
- events/package/published
Example 2:
spec:
on:
- events/package/published
- events/package/removed
# on:
# package: [published, removed]
---
do_something:
script: echo "Hello World"
-
Upsert a workflow definition to the database when new configuration gets
pushed.
Can we do it with our current rules
system?
workflow:
rules:
- events: ["package/*"]
test_package_published:
script: echo testing published package
rules:
- events: ["package/published"]
test_package_removed:
script: echo testing removed package
rules:
- events: ["package/removed"]
- We don’t upsert subscriptions to the database.
- We’ll have a single worker which runs when something happens in GitLab.
- The worker just tries to create a pipeline with the correct parameters.
- Pipeline runs when
rules
subsystem finds a job to run.
Challenges
- For every defined event run, we need to enqueue a new pipeline creation worker.
- Creating pipelines and selecting builds to run is a relatively expensive operation
- This will not work on GitLab.com scale.
In this proposal we want to create separate files for each group of events. We
can define events in the following format:
# .gitlab/ci/events/package-published.yml
spec:
events:
- name: package/published
---
include:
- local: .gitlab-ci.yml
with:
event: $[[ gitlab.event.name ]]
And in the .gitlab-ci.yml
file, we can use the input;
# .gitlab-ci.yml
spec:
inputs:
event:
default: push
---
job1:
script: echo "Hello World"
job2:
script: echo "Hello World"
job-for-package-published:
script: echo "Hello World"
rules:
- if: $[[ inputs.event ]] == "package/published"
When an event happens;
Each project can have its own configuration file for defining subscriptions to
events. For example, .gitlab-ci-event.yml
. In this file, we can define events
in the following format:
events:
- package/published
- issue/created
When this file is changed in the project repository, it is parsed and the
events are created, updated, or deleted. This is highly similar to
Proposal 1 except that we don’t need
to track pipeline creations every time.
- Upsert events to the database when
.gitlab-ci-event.yml
gets updated.
- Create inline reactions to events in code to trigger pipelines.
Filtering jobs
We can filter jobs by using the rules
keyword. For example:
In this proposal we have separate files for cohesive groups of events. The
files are being included into the main .gitlab-ci.yml
configuration file.
# my/events/packages.yaml
spec:
events:
- events/package/published
- events/audit/package/*
inputs:
env:
---
do_something:
script: ./run_for $[[ event.name ]] --env $[[ inputs.env ]]
rules:
- if: $[[ event.payload.package.name ]] == "my_package"
In the .gitlab-ci.yml
file, we can enable the subscription:
# .gitlab-ci.yml
include:
- local: my/events/packages.yaml
inputs:
env: test
GitLab will detect changes in the included files, and parse their specs. All
the information required to define a subscription will be encapsulated in the
spec, hence we will not need to read a whole file. We can easily read spec
header and calculate its checksum what can become a workflow identifier.