Coin Configuration
Qt CI for module maintainers
This section contains instructions for configuring a module to be built in the Coin CI. The module configuration consists of dependencies and instructions in YAML files that both live in the module repository and will be automatically recognized by Coin. The module dependencies must declare all dependencies that a module needs to be compiled and have its tests run.
YAML module dependencies
A module’s dependencies can be defined in a YAML file, in the top-level directory of the repository.
Example 1. Module with two dependencies. repo.git:dependencies.yaml:
dependencies:
../qtbase.git:
ref: 8155d0693f596c6b73d0acd977d5077dd7a6e6ea
required: true
../qtsvg.git:
ref: 332f9d686a08948bde82c925701a48150f29c10d
required: false
Example 2. If the module has no dependencies, the dependencies are an empty dictionary. dependencies.yaml:
dependencies:
{}
Definitions:
dependencies: dict Defines a dictionary of git repositories.
key: string URL (relative or absolute) of dependency's git repository.
ref: string Git reference of the dependency's git repository (sha1).
required: bool If set to true, the repository is direct dependency, which means that the module
will not compile without it. If set to false, the dependency is not strictly required,
but will be installed during build.
Downstream check
Downstream check will test downstream modules with current module’s sha1 updated as dependency. If the check fails, a message is posted in gerrit to the upstream module change.
Example:
downstream_check:
mode: build # build or test
modules: # Modules listed as in dependencies.yaml, dependencies in the chain will be added automatically.
../qtdeclarative:
ref: dev
configurations: # List of configuration IDs to limit the scope, omit for all configs.
- RHEL-8.4-host
Git module dependencies (deprecated)
The old module dependency declaration was defined in .gitmodules file that is internally used by git.
Example. Repository qt/qt5.git git modules file. qt5.git:.gitmodules:
...
[submodule "qtbase"]
path = qtbase
url = ../qtbase.git
branch = dev
status = essential
[submodule "qtsvg"]
depends = qtbase
path = qtsvg
url = ../qtsvg.git
branch = dev
status = addon
[submodule "qtdeclarative"]
depends = qtbase
recommends = qtsvg
path = qtdeclarative
url = ../qtdeclarative.git
branch = dev
status = essential
...
Module configuration
Module configuration is a YAML file which contains instructions that will be executed on the cloned VM. The file specifies accepted platforms, build instructions and test instructions. The relevant module configuration is all in one place, in coin folder of the module git repository:
- repo.git:
coin/module_config.yaml
Alias
Alias is used to change the name of the module. This affects the exported binary and sources package names. In modules with dependencies.yaml and alias set in qt5 .gitmodules, the alias should be also set in the module. This allows reusing the artifacts from module integrations in qt5 integrations. Alias is added on the root level:
version: 2
alias: qtbase
Includes
It is possible to include configurations from another modules or from modules own shared folder. module can have shared instructions under coin/instructions folder. Include command can be used at any part of module configuration where it is wanted to be included. These can be referenced with:
# Qtbase could have instructions under coin/instructions/prepare_build_env.yaml.
# This can be then referenced with
- !include "{{qt/qtbase}}/prepare_build_env.yaml"
- There are some limitations to includes:
Anchors are not working across includes.
The included file needs to be defined in the repository or one of it’s dependencies, in particular product lookup is not possible.
Platforms
accept_configuration tells what platforms are accepted, it has only one condition which can be nested. Typical module_config file consisting many and conditions under one or condition to specify platforms:
version: 2
accept_configuration:
condition: or
conditions:
- condition: and
conditions:
- condition: property
property: host.osVersion
in_values: [MacOS_10_13, RHEL_7_4]
- condition: property
property: host.osVersion
equals_property: target.osVersion
- condition: and
conditions:
...
instructions:
Build:
- type: SetBuildDirectory
directory: "{{.SourceDir}}"
- ...
Test:
- type: EnvironmentVariable
variableName: Dummy
variableValue: dummy
- ...
Machine Type
Machine size can be defined in yaml files in coin/platform_configs directory. COIN allows one to add features for configurations, which modifies the default VM resources. At the momenent there are four different features defined:
“VMSize4”
“VMSize8”
“VMSize16”
“DoubleSizeVM”
First three sets explicitly the number of cores allocated for the machine. Fourth one finally doubles the amount after all other rules are handled. The machine configuration in platform confiiguration yaml affects to all modules executing that configuration. Features can be added to platform configurations like this:
Configurations:
-
Template: 'qtci-linux-Ubuntu-20.04-x86_64-50'
Compiler: 'GCC'
Features: ['Sccache', 'VMSize8']
Configure arguments:....
When adding extra resources for the configuration, one should keep in mind that even if the one target might get executed faster, the whole integration may take even longer. This is because each host has limited amount of resources and even with moderate load, the requested VM may take longer to find host with enough space to fit in.
Machine size can also be defined in the module_config.yaml with machine_type property. This affects only to module itself. machine_type field has two entries ‘Build’ and ‘Test’ which define core count for build and test phases. Amount of RAM is calculated off from the core count with formula ‘3GB + core_count * 3GB’. Machine type spec allows defining only one of the entries, with the other one defaulting to either predetermined values in Coin or ultimately to 2 cores if no special rules are defined. Typical machine_type section looks like:
version: 2
accept_configuration: ...
machine_type:
Build:
cores: 8
Test:
cores: 2
Instructions
Instruction types
Each instruction must have type, required options and optionally common options.
Instruction type |
Options |
Type |
---|---|---|
ExecuteCommand |
command |
List<String> |
userMessageOnFailure |
String |
|
executeCommandArgumentSplitingBehavior |
||
ChangeDirectory
MakeDirectory
SetBuildDirectory
|
directory |
String |
WriteFile |
filename |
String |
fileContents |
String |
|
hiddenContent |
Bool |
|
fileMode |
Int |
|
EnvironmentVariable
AppendToEnvironmentVariable
PrependToEnvironmentVariable
|
variableName |
String |
variableValue |
String |
|
relativeStoragePath |
String |
|
directory |
String |
|
SetExecutionPhaseName |
executionPhaseName |
String |
RunQtUnitTest |
directory |
String |
runTestCommand |
List<String> |
|
testRepetitionAllowance |
Int |
|
UploadArtifact
UploadTestArtifact
|
archiveDirectory |
String |
transferType |
transferType |
|
UploadTestPlan |
generalTestPlanPath |
String |
qtestlibTestPlanPath |
String |
|
PrepareConanBuildInfos |
sourceDirectory |
String |
SignPackage |
directory |
String |
Rename |
sourcePath |
String |
targetPath |
String |
|
ScheduleUploadTestResults |
-
|
|
ExecuteTestPlan |
runTestCommand |
String |
relativeStoragePath |
String |
ExecuteCommand argument split
ExecuteCommand can split given arguments in two ways, before or after variables have been substituted. By default split happens before subsitution if a string is supplied and in the case of a array it is kept as it is. For example:
Env.arg = "foo bar"
# By default if a string is supplied to executeCommand it is split before substitution.
["-I {{.Env.arg}}"]
["-I", "foo bar"]
# If a list is supplied to ExecuteCommand it is kept as it is and substituted.
["-I", "-j1 {{.Env.arg}}"]
["-I", "-j1 foo bar"]
# One can also opt in for splitting after subsitution.
["-I {{.Env.arg}}"]
["-I", "foo", "bar"]
# If a list is supplied with split after option each item will be still split individually.
["-I", "-j1 {{.Env.arg}}"]
["-I", "-j1", "foo", "bar"]
Split behavior is defined with option executeCommandArgumentSplitingBehavior, default behavior being SplitBeforeVariableSubstitution.
Option |
Values |
---|---|
executeCommandArgumentSplitingBehavior |
SplitBeforeVariableSubstitution SplitAfterVariableSubstitution |
Common options for instructions
Instructions can have common fields, namingly timeouts, error message and enable condition. Timeouts are required to be set only for long running commands, since they default to 10 seconds. UserMessageOnFailure should be filled in. It is not always required (some of the commands have default message) but it is highly recommended for debugging purposes. The message should contain information about:
which step was attempted (for example: could not create directory “foo”)
what was the reason for the step (for example: the foo directory is need for shadow builds)
how a user can resolve the probem (for example: There is not known reasons for this operation to fail, please contact CI admins)
contain information if the issue is most likely caused by code or by infrastructure (for example: creating a directory failure is likely infra problem while failure in tests execution not)
Field |
Type |
Default |
Description |
---|---|---|---|
maxTimeInSeconds |
Int |
10 |
Maximum command runtime in seconds before timeout. |
maxTimeBetweenOutput |
Int |
10 |
Maximum time in seconds between output from command before timeout. |
userMessageOnFailure |
String |
Varies |
Reported error message if command fails. |
enable_if |
Condition |
None |
If provided tells whenever to include instruction. |
disable_if |
Condition |
None |
If provided tells whenever to exclude instruction. |
InstallSourceArchive
The install source archive command can take up to 5 inputs. Project, ref and directory are required where gitRemote and excludeSubModules are optional.
Gitremote tells the location of the repo, if not defined gitremote defaults to same as in the integration.
There are few keywords for the ref and project. CURRENT_BRANCH in ref field will refer to current branch. Project can be PRODUCT, this will result in qt/qt5 or qt/tqtc-qt5 in most cases. PRODUCT_REF will take the sha1 from the product in the integration, this effectively locks the ref for the integration:
type: InstallSourceArchive
gitRemote: qt-project
project: PRODUCT
ref: PRODUCT_ref
directory: qt5-repo
maxTimeInSeconds: 300
maxTimeBetweenOutput: 300
excludeSubModules: true
userMessageOnFailure: "Could not install x source archive."
Instruction groups
Instruction groups can be created by defining item with type group and instructions field. Groups are useful in sharing enable_if for multiple instructions and yaml anchors for deduplicating instructions between build and test:
type: Group
instructions:
...
enable_if:
...
Group and/or instructions can be tied to anchor per yaml specification:
gcc_make_instructions: &gcc_make_instructions
type: Group
instructions:
...
# Which can be later referenced with
- *gcc_make_instructions
Conditions
Conditions are used to define accepted platforms and inclusion of instructions. instructions and groups use enable_if to specify their condition. typical instruction with a condition:
- type: SignPackage
directory: "package/dir"
enable_if:
condition: property
property: host.os
equals_value: Windows
Condition types
Multiple condition types exists. This makes it possible to have nested conditions. Property condition has rule under it and (and, or) conditions have list of conditions specified under them.
Condition type |
Description |
---|---|
property |
Condition which specifies rule for certain property. |
runtime |
Condition which is evaluated at runtime. |
and |
All child conditions must return true. |
or |
True when any of child conditions returns true. |
Condition Properties
Property conditions have a property from workitemconfiguration which then is evaluated with specified rule. Workitemconfiguration and the possible values for platforms and features are specified in Properties. Workitemconfiguration fields can be used in property and subproperties of those accessed with a dot.
Condition rules
Property condition can use different rules but only one at a time. These are:
Condition rule |
Type |
Description |
---|---|---|
equals_value |
Any |
True if given value equals the condition property. |
not_equals_value |
Any |
True if given value does not equals the condition property. |
equals_property |
Any |
True if given property equals the condition property. |
not_equals_property |
Any |
True if given property does not equal the condition property. |
in_values |
List<Any> |
True if condition property matches any value in given list. |
not_in_values |
List<Any> |
True if condition property does not exists in given list. |
contains_value |
Any |
True if condition property contains given value. |
not_contains_value |
Any |
True if condition property does not contain given value |
Runtime conditions
Runtime conditions can be used to include or exclude instructions based on environment variables. Only equals_value, not_equals_value, contains_value and not_contains_value operators are accepted for runtime conditions. Example:
enable_if:
condition: runtime
env_var: foo-bar
equals_value: baz
Environment Variables
Environment variables can be referred in multiple ways in coin instructions. The regular environment variables can be referred like:
"{{.Env.<environment variable>}}"
Coin also offers some variables related to build environment, which are not in regular environment variables these are agentWorkingDir, sourceDir, buildDir, testDir, installDir, installRoot and testResultsDir. These can be used in two ways either with {{.<option>}} which returns path without volume label and formats it, this requires using capitalized first letter for option:
"echo {{.SourceDir}}"
Other option includes volume labels, does not do any formatting and enables access to agentID, buildKey and currentExecutionPhase in addition to above variables. Note that all variable names are case sensetive in this case:
'echo {{.AgentVariable "sourceDir"}}'
Qt CI for platform maintainers
This is how you check what’s going on for a specific platform.
Sometimes certain platforms require certain libraries to be installed or other aspects of the system that implements the platform to be configured. For example choosing a specific ICU version for a specific Qt version.
Adjustments to the operating system installation by modifying system files or installing third-party software is done through provisioning, which allows making customizations that apply to specific Qt versions. It is possible for example to use one version of ICU for Qt 5.6 and another version of ICU for Qt 5.7 without them conflicting. This is implemented by using different virtual machine templates for different minor versions. The provisioning is run as the first step during integrations. The provisioning scripts are stored in the product in most cases qt5 repo under coin/provisioning.
The provisioning will take the base operating system templates, apply Qt version specific changes and save them in a new clone, which will be used for building and testing.
Platform Configurations
Platforms which are used to build and test in coin are defined in the yaml files under coin/platform_configurations in product repo, which in most cases is the qt5 repo.
The platforms are defined as follows:
Version: 2
Module only: True
Configurations:
-
Id: 'RHEL-8.4-host'
Template: 'qtci-linux-RHEL-8.4-x86_64-50'
Compiler: 'GCC'
Features: ['Packaging', 'Sccache']
Configure arguments: '-DQT_BUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo'
Environment variables: ['CONAN_PROFILE=coin/conan/profiles/linux-x86_64-gcc']
- ...
It is possible to include other platforms from different files in 2 ways by adding include at root level. Either including whole file:
Include: [
cmake_platforms.yaml,
cmake_platforms_target_android_host_linux.yaml,
]
Or by including only some configurations by id from said file:
Include: [
cmake_platforms.yaml: [
"Windows10_21H2-Mingw11-x64-host",
"RHEL-8.4-host"
],
cmake_platforms_target_android_host_linux.yaml: [
"android-x86-tests"
]
]
The id based include is efficient in defining the precheck.yaml, which lists configurations run in the default precheck.
It is possible to override some properties of included configurations with override. Given values are directly replaced on configuration with matching id in included configs:
Version: 2
Configurations: []
Include: [
macos.yaml
]
Overrides:
-
Id: 'macos-14-arm64-developer-build-tests'
Features: ['TestOnly']
Qt CI for people administrating the CI
For the short version, how to run the CI, jump over to Administration of Coin.