diff --git a/.gitlab/ci/jobs/packaging/opam_package.yml b/.gitlab/ci/jobs/packaging/opam_package.yml index 230901aefbda59cc250656a7eaf6429b73ba3731..4e6e261feb840e69fcdc53c45ec2224045ebf2e2 100644 --- a/.gitlab/ci/jobs/packaging/opam_package.yml +++ b/.gitlab/ci/jobs/packaging/opam_package.yml @@ -414,6 +414,8 @@ opam:bls12-381: variables: package: bls12-381 +# Ignoring unreleased package gitlab_ci. + # Ignoring unreleased package internal-devtools. # Ignoring unreleased package internal-devtools_proto-context-du. diff --git a/Makefile b/Makefile index d4e841bb004a76616a74848253df666300b01eed..17ae0cdce290387cdf8bfa076e59037a8e66ee64 100644 --- a/Makefile +++ b/Makefile @@ -268,7 +268,7 @@ test-protocol-compile: PROTO_DIRS := $(shell find src/ -maxdepth 1 -type d -path "src/proto_*" 2>/dev/null | LC_COLLATE=C sort) NONPROTO_DIRS := $(shell find src/ -maxdepth 1 -mindepth 1 -type d -not -path "src/proto_*" 2>/dev/null | LC_COLLATE=C sort) -OTHER_DIRS := $(shell find contrib/ -maxdepth 1 -mindepth 1 -type d 2>/dev/null | LC_COLLATE=C sort) +OTHER_DIRS := $(shell find contrib/ ci/ -maxdepth 1 -mindepth 1 -type d 2>/dev/null | LC_COLLATE=C sort) .PHONY: test-proto-unit test-proto-unit: diff --git a/ci/README.md b/ci/README.md new file mode 100644 index 0000000000000000000000000000000000000000..513cb09cec45501b720c13541d71895e7bea3699 --- /dev/null +++ b/ci/README.md @@ -0,0 +1,9 @@ +# CI-in-OCaml + +This directory contains an OCaml library for writing generators of +GitLab CI configuration files (i.e. `.gitlab-ci.yml`). + +This directory is structured like this: + + - `lib_gitlab_ci`: contains a partial, slightly opiniated, AST of + [GitLab CI/CD YAML syntax](https://docs.gitlab.com/ee/ci/yaml/). diff --git a/ci/lib_gitlab_ci/base.ml b/ci/lib_gitlab_ci/base.ml new file mode 100644 index 0000000000000000000000000000000000000000..4c3192365328a486d2cad1916217ae3e88b549b6 --- /dev/null +++ b/ci/lib_gitlab_ci/base.ml @@ -0,0 +1,68 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(* A set of definitions borrowed from Tezt's [lib_core/base.ml] *) + +let sf = Format.asprintf + +let ( // ) = Filename.concat + +module String_set = Set.Make (String) +module String_map = Map.Make (String) + +let with_open_out file write_f = + let chan = open_out file in + try + write_f chan ; + close_out chan + with x -> + close_out chan ; + raise x + +let with_open_in file read_f = + let chan = open_in file in + try + let value = read_f chan in + close_in chan ; + value + with x -> + close_in chan ; + raise x + +let write_file filename ~contents = + with_open_out filename @@ fun ch -> output_string ch contents + +let project_root = + match Sys.getenv_opt "DUNE_SOURCEROOT" with + | Some x -> x + | None -> ( + match Sys.getenv_opt "PWD" with + | Some x -> x + | None -> + (* For some reason, under [dune runtest], [PWD] and + [getcwd] have different values. [getcwd] is in + [_build/default], and [PWD] is where [dune runtest] was + executed, which is closer to what we want. *) + Sys.getcwd ()) + +let write_yaml ?(header = "") filename yaml = + let contents = + header + ^ + match Yaml.to_string ~encoding:`Utf8 ~scalar_style:`Plain yaml with + | Ok s -> s + | Error (`Msg error_msg) -> + failwith + ("Could not convert JSON configuration to YAML string: " ^ error_msg) + in + write_file filename ~contents + +let range a b = + let rec range ?(acc = []) a b = + if b < a then acc else range ~acc:(b :: acc) a (b - 1) + in + range a b diff --git a/ci/lib_gitlab_ci/dune b/ci/lib_gitlab_ci/dune new file mode 100644 index 0000000000000000000000000000000000000000..bbe4a4161fa9946847589cf4ef73ed41393ca60e --- /dev/null +++ b/ci/lib_gitlab_ci/dune @@ -0,0 +1,10 @@ +; This file was automatically generated, do not edit. +; Edit file manifest/main.ml instead. + +(library + (name gitlab_ci) + (public_name gitlab_ci) + (libraries + yaml) + (inline_tests (flags -verbose) (modes native)) + (preprocess (pps ppx_expect))) diff --git a/ci/lib_gitlab_ci/expect_tests.ml b/ci/lib_gitlab_ci/expect_tests.ml new file mode 100644 index 0000000000000000000000000000000000000000..f80af7b5ce01124505aedacda3cf41671ec4cb44 --- /dev/null +++ b/ci/lib_gitlab_ci/expect_tests.ml @@ -0,0 +1,93 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(* used only for hosting tests *) + +(** {2 Test {!To_yaml}} *) + +let%expect_test _ = + let p config = + match To_yaml.to_yaml config |> Yaml.to_string with + | Error (`Msg msg) -> Format.printf "ERROR: %s\n" msg + | Ok s -> print_endline s + in + p [] ; + [%expect {| + {} |}] ; + p + [ + Workflow + { + rules = [Util.workflow_rule ~if_:If.(var "CI_SETTING" == null) ()]; + name = Some "setting_not_set"; + }; + ] ; + [%expect + {| + workflow: + name: setting_not_set + rules: + - if: $CI_SETTING == null + when: always |}] ; + p + [ + Types.Default + {image = Some (Image "alpine-or-something"); interruptible = Some false}; + Types.Stages ["first"]; + Types.Include + [ + {local = "foo"; rules = []}; + {local = "bar"; rules = [Util.include_rule ~changes:["src/**/*"] ()]}; + ]; + Variables [("k1", "v"); ("k2", "vv")]; + Types.Job + (Util.job + ~stage:"first" + ~name:"jobbbbbbb" + ~script:["rm -rf /"; "echo it is all gone now"] + ()); + ] ; + [%expect + {| + default: + image: alpine-or-something + interruptible: false + stages: + - first + include: + - foo + - local: bar + rules: + - changes: + - src/**/* + when: always + variables: + k1: v + k2: vv + jobbbbbbb: + stage: first + script: + - rm -rf / + - echo it is all gone now |}] ; + () + +(** {2 Test {!If}-expressions} *) + +let%expect_test _ = + let p f_expr = + try print_endline (If.encode (Lazy.force f_expr)) + with Invalid_argument msg -> print_endline ("Invalid_argument: " ^ msg) + in + p @@ lazy If.(var "Göteborg" == null) ; + [%expect {| Invalid_argument: [Var.t] invalid variable name 'Göteborg' |}] ; + p @@ lazy If.(var "foo" == str "This \"example\" is ok") ; + [%expect {| $foo == 'This "example" is ok' |}] ; + p @@ lazy If.(var "foo" == str "This 'example' is ok") ; + [%expect {| $foo == "This 'example' is ok" |}] ; + p @@ lazy If.(var "foo" == str "This \"example\" is 'not ok'") ; + [%expect + {| Invalid_argument: [If.str] literal strings cannot mix single and double-quotes, got "This \"example\" is 'not ok'". |}] diff --git a/ci/lib_gitlab_ci/if.ml b/ci/lib_gitlab_ci/if.ml new file mode 100644 index 0000000000000000000000000000000000000000..5ca99e71df2a654bbc77245ddbf7fd979f27372f --- /dev/null +++ b/ci/lib_gitlab_ci/if.ml @@ -0,0 +1,102 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +open Base + +type term = Str of string | Null + +type t = + | And of t * t + | Or of t * t + | Eq of Var.t * term + | Neq of Var.t * term + | Match of Var.t * string + | Unmatch of Var.t * string + +let var = Var.make + +let rec encode expr = + let prio = function + | Eq _ -> 1 + | Neq _ -> 1 + | Match _ -> 1 + | Unmatch _ -> 1 + | And _ -> 2 + | Or _ -> 3 + in + (* Precedence: not > and > or > string, var + + And (Or a b) c -> (a || b) && c + Or a (And b c) -> a || b && c + Or (And a b) c -> a && b || c *) + let paren_opt sub_expr = + let s = encode sub_expr in + if prio expr < prio sub_expr then "(" ^ s ^ ")" else s + in + let encode_term = function + | Null -> "null" + | Str s -> + (* Strings can be enclosed by single or double quotes, see + https://docs.gitlab.com/ee/ci/jobs/job_control.html#compare-a-variable-to-a-string. + + To encode strings that do not contain double quotes, we + enclose them with double quotes. To encode strings that do + not contain single quotes, we enclose with single + quotes. The smart constructor {!str} for strings ensure + that strings do not contain both single and double quotes, + as such strings cannot be encoded. *) + if not (String.contains s '"') then sf {|"%s"|} s + else if not (String.contains s '\'') then sf {|'%s'|} s + else + (* This branch cannot be reached for [Str]s created by + {!str}. *) + assert false + in + match expr with + | And (a, b) -> sf "%s && %s" (paren_opt a) (paren_opt b) + | Or (a, b) -> sf "%s || %s" (paren_opt a) (paren_opt b) + | Eq (a, b) -> sf "%s == %s" (Var.encode a) (encode_term b) + | Neq (a, b) -> sf "%s != %s" (Var.encode a) (encode_term b) + | Match (a, b) -> sf "%s =~ %s" (Var.encode a) b + | Unmatch (a, b) -> sf "%s !~ %s" (Var.encode a) b + +let eq a b = Eq (a, b) + +let neq a b = Neq (a, b) + +let and_ a b = And (a, b) + +let or_ a b = Or (a, b) + +let str s = + (* See {{:https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/pipeline/expression/lexeme/string.rb#L9}string.rb}}. *) + if String.contains s '"' && String.contains s '\'' then + raise + (Invalid_argument + (sf + "[If.str] literal strings cannot mix single and double-quotes, got \ + %S." + s)) ; + Str s + +let null = Null + +let match_ a b = Match (a, b) + +let unmatch a b = Unmatch (a, b) + +let ( == ) = eq + +let ( != ) = neq + +let ( && ) = and_ + +let ( || ) = or_ + +let ( =~ ) = match_ + +let ( =~! ) = unmatch diff --git a/ci/lib_gitlab_ci/if.mli b/ci/lib_gitlab_ci/if.mli new file mode 100644 index 0000000000000000000000000000000000000000..f4ecc535fd3cf56d240c2d3d41989a12dea7720e --- /dev/null +++ b/ci/lib_gitlab_ci/if.mli @@ -0,0 +1,73 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** GitLab CI variable expressions + + For more information, see + {{:https://docs.gitlab.com/ee/ci/jobs/job_control.html#cicd-variable-expressions} + here}. *) + +(** Predicates for GitLab [if:] expression, as used in [rules:] clauses. *) +type t + +(** Terms for predicates in GitLab [if:] clauses. *) +type term + +(** The string representation of an [if:] expression. *) +val encode : t -> string + +(** [var name] is the [if:] expression [$name]. + + This is an alias of {!Var.make} to simplify usage of variables in + [if:] expressions. It allows you to write e.g. + {{ + If.(var "foo" == "bar") + }} + instead of + {{ + If.(Var.make "foo" == "bar") + }} + + Raises [Invalid_argument] if the variable name is not composed + exclusively of characters from the set [a-zA-Z0-9_]. *) +val var : string -> Var.t + +(** [str s] is the [if:] expression ["s"]. + + Raises [Invalid_argument] if the literal string contains both + single and double quotes. Such strings cannot be encoded in GitLab + CI [if:] expressions. *) +val str : string -> term + +(** The [if:]-expression [null]. *) +val null : term + +(** Equality in [if:]-expressions. + + Example: [var "foo" == str "bar"] translates to [$foo == "bar"]. *) +val ( == ) : Var.t -> term -> t + +(** Inequality in [if:]-expressions. + + Example: [var "foo" != str "bar"] translates to [$foo != "bar"]. *) +val ( != ) : Var.t -> term -> t + +(** Conjunction of [if:]-expressions. *) +val ( && ) : t -> t -> t + +(** Disjunction of [if:]-expressions. *) +val ( || ) : t -> t -> t + +(** Pattern match on [if:]-expressions. + + Example: [var "foo" =~ str "/bar/"] translates to [$foo =~ "/bar/"]. *) +val ( =~ ) : Var.t -> string -> t + +(** Negated pattern match on [if:]-expressions. + + Example: [var "foo" =~! str "/bar/"] translates to [$foo !~ "/bar/"]. *) +val ( =~! ) : Var.t -> string -> t diff --git a/ci/lib_gitlab_ci/make_predefined_vars.sh b/ci/lib_gitlab_ci/make_predefined_vars.sh new file mode 100755 index 0000000000000000000000000000000000000000..c00536b14af18cc86ffae81033ddd39ca00f2f58 --- /dev/null +++ b/ci/lib_gitlab_ci/make_predefined_vars.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +if [ "$1" = "--help" ] || [ "$#" -gt 1 ]; then + cat << EOT +Usage: $0 + +Writes the files 'predefined_vars.ml' and 'predefined_vars.mli' based +on the contents of the files 'predefined_vars.csv' and +'predefined_mr_vars.csv'. +EOT + exit 1 +fi + +rm -f predefined_vars.ml predefined_vars.mli + +cat >> predefined_vars.mli << EOT +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** Predefined CI/CD variables in all pipelines. + + This contains a subset of the + {{:https://docs.gitlab.com/ee/ci/variables/predefined_variables.html} + predefined variables}. *) + +(** String representation of a variable with the sigil-sign. + + A handy alias of [If.encode_var]. *) +val show : Var.t -> string + +EOT + +cat >> predefined_vars.ml << EOT +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(* This file is generated. + + See [make_predefined_vars.sh] in this directory for more information. *) + +open Var + +let show = encode + +EOT + +grep -v Deprecated predefined_vars.csv | while read -r line; do + var=$(echo "$line" | cut -f 1 | xargs) + var_lower=$(echo "$var" | tr '[:upper:]' '[:lower:]') + defined_for=$(echo "$line" | cut -f 2 | xargs) + gitlab_version=$(echo "$line" | cut -f 3 | xargs) + runner=$(echo "$line" | cut -f 4 | xargs) + description=$(echo "$line" | cut -f 5 | xargs | fold --spaces --width 76 | sed "s/^/ /g") + + cat >> predefined_vars.mli << EOT +(** Corresponds to [${var}]. + +${description} + + Context: [${defined_for}]. Available since GitLab [${gitlab_version}]. + Available in [${runner}] runners. *) +val ${var_lower} : Var.t + +EOT + cat >> predefined_vars.ml << EOT +let ${var_lower} = make "${var}" + +EOT +done + +echo "(** {2 Predefined variables for merge request pipelines} *)" >> predefined_vars.mli +echo >> predefined_vars.mli + +grep -v Deprecated predefined_mr_vars.csv | while read -r line; do + var=$(echo "$line" | cut -f 1 | xargs) + var_lower=$(echo "$var" | tr '[:upper:]' '[:lower:]') + gitlab_version=$(echo "$line" | cut -f 2 | xargs) + runner=$(echo "$line" | cut -f 3 | xargs) + description=$(echo "$line" | cut -f 4 | xargs | fold --spaces --width 76 | sed "s/^/ /g") + + cat >> predefined_vars.mli << EOT +(** Corresponds to [${var}]. + +${description} + + Context: merge requests. Available since GitLab [${gitlab_version}]. + Available in [${runner}] runners. *) +val ${var_lower} : Var.t + +EOT + cat >> predefined_vars.ml << EOT +let ${var_lower} = make "${var}" + +EOT +done + +sed -i 's/ \+$//' predefined_vars.ml predefined_vars.mli +ocamlformat -i predefined_vars.ml predefined_vars.mli diff --git a/ci/lib_gitlab_ci/predefined_mr_vars.csv b/ci/lib_gitlab_ci/predefined_mr_vars.csv new file mode 100644 index 0000000000000000000000000000000000000000..b463deae9d000dc0c04adb1716139d5ffc950924 --- /dev/null +++ b/ci/lib_gitlab_ci/predefined_mr_vars.csv @@ -0,0 +1,26 @@ +CI_MERGE_REQUEST_APPROVED 14.1 all Approval status of the merge request. true when merge request approvals is available and the merge request has been approved. +CI_MERGE_REQUEST_ASSIGNEES 11.9 all Comma-separated list of usernames of assignees for the merge request. +CI_MERGE_REQUEST_DIFF_BASE_SHA 13.7 all The base SHA of the merge request diff. +CI_MERGE_REQUEST_DIFF_ID 13.7 all The version of the merge request diff. +CI_MERGE_REQUEST_EVENT_TYPE 12.3 all The event type of the merge request. Can be detached, merged_result or merge_train. +CI_MERGE_REQUEST_DESCRIPTION 16.7 all The description of the merge request. If the description is more than 2700 characters long, only the first 2700 characters are stored in the variable. +CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED 16.8 all true if CI_MERGE_REQUEST_DESCRIPTION is truncated down to 2700 characters because the description of the merge request is too long. +CI_MERGE_REQUEST_ID 11.6 all The instance-level ID of the merge request. This is a unique ID across all projects on the GitLab instance. +CI_MERGE_REQUEST_IID 11.6 all The project-level IID (internal ID) of the merge request. This ID is unique for the current project, and is the number used in the merge request URL, page title, and other visible locations. +CI_MERGE_REQUEST_LABELS 11.9 all Comma-separated label names of the merge request. +CI_MERGE_REQUEST_MILESTONE 11.9 all The milestone title of the merge request. +CI_MERGE_REQUEST_PROJECT_ID 11.6 all The ID of the project of the merge request. +CI_MERGE_REQUEST_PROJECT_PATH 11.6 all The path of the project of the merge request. For example namespace/awesome-project. +CI_MERGE_REQUEST_PROJECT_URL 11.6 all The URL of the project of the merge request. For example, http://192.168.10.15:3000/namespace/awesome-project. +CI_MERGE_REQUEST_REF_PATH 11.6 all The ref path of the merge request. For example, refs/merge-requests/1/head. +CI_MERGE_REQUEST_SOURCE_BRANCH_NAME 11.6 all The source branch name of the merge request. +CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED 16.4 all true when the source branch of the merge request is protected. +CI_MERGE_REQUEST_SOURCE_BRANCH_SHA 11.9 all The HEAD SHA of the source branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in merged results pipelines. +CI_MERGE_REQUEST_SOURCE_PROJECT_ID 11.6 all The ID of the source project of the merge request. +CI_MERGE_REQUEST_SOURCE_PROJECT_PATH 11.6 all The path of the source project of the merge request. +CI_MERGE_REQUEST_SOURCE_PROJECT_URL 11.6 all The URL of the source project of the merge request. +CI_MERGE_REQUEST_SQUASH_ON_MERGE 16.4 all true when the squash on merge option is set. +CI_MERGE_REQUEST_TARGET_BRANCH_NAME 11.6 all The target branch name of the merge request. +CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED 15.2 all true when the target branch of the merge request is protected. +CI_MERGE_REQUEST_TARGET_BRANCH_SHA 11.9 all The HEAD SHA of the target branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in merged results pipelines. +CI_MERGE_REQUEST_TITLE 11.9 all The title of the merge request. diff --git a/ci/lib_gitlab_ci/predefined_vars.csv b/ci/lib_gitlab_ci/predefined_vars.csv new file mode 100644 index 0000000000000000000000000000000000000000..637111e1a6f30356742b90be192a0feb8ddac0a4 --- /dev/null +++ b/ci/lib_gitlab_ci/predefined_vars.csv @@ -0,0 +1,123 @@ +CHAT_CHANNEL Pipeline 10.6 all The Source chat channel that triggered the ChatOps command. +CHAT_INPUT Pipeline 10.6 all The additional arguments passed with the ChatOps command. +CHAT_USER_ID Pipeline 14.4 all The chat service’s user ID of the user who triggered the ChatOps command. +CI Pipeline all 0.4 Available for all jobs executed in CI/CD. true when available. +CI_API_V4_URL Pipeline 11.7 all The GitLab API v4 root URL. +CI_API_GRAPHQL_URL Pipeline 15.11 all The GitLab API GraphQL root URL. +CI_BUILDS_DIR Jobs only all 11.10 The top-level directory where builds are executed. +CI_COMMIT_AUTHOR Pipeline 13.11 all The author of the commit in Name format. +CI_COMMIT_BEFORE_SHA Pipeline 11.2 all The previous latest commit present on a branch or tag. Is always 0000000000000000000000000000000000000000 for merge request pipelines, the first commit in pipelines for branches or tags, or when manually running a pipeline. +CI_COMMIT_BRANCH Pipeline 12.6 0.5 The commit branch name. Available in branch pipelines, including pipelines for the default branch. Not available in merge request pipelines or tag pipelines. +CI_COMMIT_DESCRIPTION Pipeline 10.8 all The description of the commit. If the title is shorter than 100 characters, the message without the first line. +CI_COMMIT_MESSAGE Pipeline 10.8 all The full commit message. +CI_COMMIT_REF_NAME Pipeline 9.0 all The branch or tag name for which project is built. +CI_COMMIT_REF_PROTECTED Pipeline 11.11 all true if the job is running for a protected reference, false otherwise. +CI_COMMIT_REF_SLUG Pipeline 9.0 all CI_COMMIT_REF_NAME in lowercase, shortened to 63 bytes, and with everything except 0-9 and a-z replaced with -. No leading / trailing -. Use in URLs, host names and domain names. +CI_COMMIT_SHA Pipeline 9.0 all The commit revision the project is built for. +CI_COMMIT_SHORT_SHA Pipeline 11.7 all The first eight characters of CI_COMMIT_SHA. +CI_COMMIT_TAG Pipeline 9.0 0.5 The commit tag name. Available only in pipelines for tags. +CI_COMMIT_TAG_MESSAGE Pipeline 15.5 all The commit tag message. Available only in pipelines for tags. +CI_COMMIT_TIMESTAMP Pipeline 13.4 all The timestamp of the commit in the ISO 8601 format. For example, 2022-01-31T16:47:55Z. +CI_COMMIT_TITLE Pipeline 10.8 all The title of the commit. The full first line of the message. +CI_CONCURRENT_ID Jobs only all 11.10 The unique ID of build execution in a single executor. +CI_CONCURRENT_PROJECT_ID Jobs only all 11.10 The unique ID of build execution in a single executor and project. +CI_CONFIG_PATH Pipeline 9.4 0.5 The path to the CI/CD configuration file. Defaults to .gitlab-ci.yml. Read-only inside a running pipeline. +CI_DEBUG_TRACE Pipeline all 1.7 true if debug logging (tracing) is enabled. +CI_DEBUG_SERVICES Pipeline 15.7 15.7 true if service container logging is enabled. +CI_DEFAULT_BRANCH Pipeline 12.4 all The name of the project’s default branch. +CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX Pipeline 14.3 all The direct group image prefix for pulling images through the Dependency Proxy. +CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX Pipeline 13.7 all The top-level group image prefix for pulling images through the Dependency Proxy. +CI_DEPENDENCY_PROXY_PASSWORD Pipeline 13.7 all The password to pull images through the Dependency Proxy. +CI_DEPENDENCY_PROXY_SERVER Pipeline 13.7 all The server for logging in to the Dependency Proxy. This is equivalent to $CI_SERVER_HOST:$CI_SERVER_PORT. +CI_DEPENDENCY_PROXY_USER Pipeline 13.7 all The username to pull images through the Dependency Proxy. +CI_DEPLOY_FREEZE Pipeline 13.2 all Only available if the pipeline runs during a deploy freeze window. true when available. +CI_DEPLOY_PASSWORD Jobs only 10.8 all The authentication password of the GitLab Deploy Token, if the project has one. +CI_DEPLOY_USER Jobs only 10.8 all The authentication username of the GitLab Deploy Token, if the project has one. +CI_DISPOSABLE_ENVIRONMENT Pipeline all 10.1 Only available if the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except shell and ssh). true when available. +CI_ENVIRONMENT_NAME Pipeline 8.15 all The name of the environment for this job. Available if environment:name is set. +CI_ENVIRONMENT_SLUG Pipeline 8.15 all The simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, and so on. Available if environment:name is set. The slug is truncated to 24 characters. A random suffix is automatically added to uppercase environment names. +CI_ENVIRONMENT_URL Pipeline 9.3 all The URL of the environment for this job. Available if environment:url is set. +CI_ENVIRONMENT_ACTION Pipeline 13.11 all The action annotation specified for this job’s environment. Available if environment:action is set. Can be start, prepare, or stop. +CI_ENVIRONMENT_TIER Pipeline 14.0 all The deployment tier of the environment for this job. +CI_RELEASE_DESCRIPTION Pipeline 15.5 all The description of the release. Available only on pipelines for tags. Description length is limited to first 1024 characters. +CI_GITLAB_FIPS_MODE Pipeline 14.10 all Only available if FIPS mode is enabled in the GitLab instance. true when available. +CI_HAS_OPEN_REQUIREMENTS Pipeline 13.1 all Only available if the pipeline’s project has an open requirement. true when available. +CI_JOB_ID Jobs only 9.0 all The internal ID of the job, unique across all jobs in the GitLab instance. +CI_JOB_IMAGE Pipeline 12.9 12.9 The name of the Docker image running the job. +CI_JOB_JWT (Deprecated) Pipeline 12.10 all A RS256 JSON web token to authenticate with third party systems that support JWT authentication, for example HashiCorp’s Vault. Deprecated in GitLab 15.9 and scheduled to be removed in GitLab 17.0. Use ID tokens instead. +CI_JOB_JWT_V1 (Deprecated) Pipeline 14.6 all The same value as CI_JOB_JWT. Deprecated in GitLab 15.9 and scheduled to be removed in GitLab 17.0. Use ID tokens instead. +CI_JOB_JWT_V2 (Deprecated) Pipeline 14.6 all A newly formatted RS256 JSON web token to increase compatibility. Similar to CI_JOB_JWT, except the issuer (iss) claim is changed from gitlab.com to https://gitlab.com, sub has changed from job_id to a string that contains the project path, and an aud claim is added. The aud field is a constant value. Trusting JWTs in multiple relying parties can lead to one RP sending a JWT to another one and acting maliciously as a job. Deprecated in GitLab 15.9 and scheduled to be removed in GitLab 17.0. Use ID tokens instead. +CI_JOB_MANUAL Pipeline 8.12 all Only available if the job was started manually. true when available. +CI_JOB_NAME Pipeline 9.0 0.5 The name of the job. +CI_JOB_NAME_SLUG Pipeline 15.4 all CI_JOB_NAME in lowercase, shortened to 63 bytes, and with everything except 0-9 and a-z replaced with -. No leading / trailing -. Use in paths. +CI_JOB_STAGE Pipeline 9.0 0.5 The name of the job’s stage. +CI_JOB_STATUS Jobs only all 13.5 The status of the job as each runner stage is executed. Use with after_script. Can be success, failed, or canceled. +CI_JOB_TIMEOUT Jobs only 15.7 15.7 The job timeout, in seconds. +CI_JOB_TOKEN Jobs only 9.0 1.2 A token to authenticate with certain API endpoints. The token is valid as long as the job is running. +CI_JOB_URL Jobs only 11.1 0.5 The job details URL. +CI_JOB_STARTED_AT Jobs only 13.10 all The UTC datetime when a job started, in ISO 8601 format. For example, 2022-01-31T16:47:55Z. +CI_KUBERNETES_ACTIVE Pipeline 13.0 all Only available if the pipeline has a Kubernetes cluster available for deployments. true when available. +CI_NODE_INDEX Pipeline 11.5 all The index of the job in the job set. Only available if the job uses parallel. +CI_NODE_TOTAL Pipeline 11.5 all The total number of instances of this job running in parallel. Set to 1 if the job does not use parallel. +CI_OPEN_MERGE_REQUESTS Pipeline 13.8 all A comma-separated list of up to four merge requests that use the current branch and project as the merge request source. Only available in branch and merge request pipelines if the branch has an associated merge request. For example, gitlab-org/gitlab!333,gitlab-org/gitlab-foss!11. +CI_PAGES_DOMAIN Pipeline 11.8 all The configured domain that hosts GitLab Pages. +CI_PAGES_URL Pipeline 11.8 all The URL for a GitLab Pages site. Always a subdomain of CI_PAGES_DOMAIN. +CI_PIPELINE_ID Jobs only 8.10 all The instance-level ID of the current pipeline. This ID is unique across all projects on the GitLab instance. +CI_PIPELINE_IID Pipeline 11.0 all The project-level IID (internal ID) of the current pipeline. This ID is unique only within the current project. +CI_PIPELINE_SOURCE Pipeline 10.0 all How the pipeline was triggered. Can be push, web, schedule, api, external, chat, webide, merge_request_event, external_pull_request_event, parent_pipeline, trigger, or pipeline. For a description of each value, see Common if clauses for rules, which uses this variable to control when jobs run. +CI_PIPELINE_TRIGGERED Pipeline all all true if the job was triggered. +CI_PIPELINE_URL Jobs only 11.1 0.5 The URL for the pipeline details. +CI_PIPELINE_CREATED_AT Pipeline 13.10 all The UTC datetime when the pipeline was created, in ISO 8601 format. For example, 2022-01-31T16:47:55Z. +CI_PIPELINE_NAME Pipeline 16.3 all The pipeline name defined in workflow:name +CI_PROJECT_DIR Jobs only all all The full path the repository is cloned to, and where the job runs from. If the GitLab Runner builds_dir parameter is set, this variable is set relative to the value of builds_dir. For more information, see the Advanced GitLab Runner configuration. +CI_PROJECT_ID Pipeline all all The ID of the current project. This ID is unique across all projects on the GitLab instance. +CI_PROJECT_NAME Pipeline 8.10 0.5 The name of the directory for the project. For example if the project URL is gitlab.example.com/group-name/project-1, CI_PROJECT_NAME is project-1. +CI_PROJECT_NAMESPACE Pipeline 8.10 0.5 The project namespace (username or group name) of the job. +CI_PROJECT_NAMESPACE_ID Pipeline 15.7 0.5 The project namespace ID of the job. +CI_PROJECT_PATH_SLUG Pipeline 9.3 all $CI_PROJECT_PATH in lowercase with characters that are not a-z or 0-9 replaced with - and shortened to 63 bytes. Use in URLs and domain names. +CI_PROJECT_PATH Pipeline 8.10 0.5 The project namespace with the project name included. +CI_PROJECT_REPOSITORY_LANGUAGES Pipeline 12.3 all A comma-separated, lowercase list of the languages used in the repository. For example ruby,javascript,html,css. The maximum number of languages is limited to 5. An issue proposes to increase the limit. +CI_PROJECT_ROOT_NAMESPACE Pipeline 13.2 0.5 The root project namespace (username or group name) of the job. For example, if CI_PROJECT_NAMESPACE is root-group/child-group/grandchild-group, CI_PROJECT_ROOT_NAMESPACE is root-group. +CI_PROJECT_TITLE Pipeline 12.4 all The human-readable project name as displayed in the GitLab web interface. +CI_PROJECT_DESCRIPTION Pipeline 15.1 all The project description as displayed in the GitLab web interface. +CI_PROJECT_URL Pipeline 8.10 0.5 The HTTP(S) address of the project. +CI_PROJECT_VISIBILITY Pipeline 10.3 all The project visibility. Can be internal, private, or public. +CI_PROJECT_CLASSIFICATION_LABEL Pipeline 14.2 all The project external authorization classification label. +CI_REGISTRY Pipeline 8.10 0.5 Address of the container registry server, formatted as [:]. For example: registry.gitlab.example.com. Only available if the container registry is enabled for the GitLab instance. +CI_REGISTRY_IMAGE Pipeline 8.10 0.5 Base address for the container registry to push, pull, or tag project’s images, formatted as [:]/. For example: registry.gitlab.example.com/my_group/my_project. Image names must follow the container registry naming convention. Only available if the container registry is enabled for the project. +CI_REGISTRY_PASSWORD Jobs only 9.0 all The password to push containers to the GitLab project’s container registry. Only available if the container registry is enabled for the project. This password value is the same as the CI_JOB_TOKEN and is valid only as long as the job is running. Use the CI_DEPLOY_PASSWORD for long-lived access to the registry +CI_REGISTRY_USER Jobs only 9.0 all The username to push containers to the project’s GitLab container registry. Only available if the container registry is enabled for the project. +CI_REPOSITORY_URL Jobs only 9.0 all The full path to Git clone (HTTP) the repository with a CI/CD job token, in the format https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.example.com/my-group/my-project.git. +CI_RUNNER_DESCRIPTION Jobs only 8.10 0.5 The description of the runner. +CI_RUNNER_EXECUTABLE_ARCH Jobs only all 10.6 The OS/architecture of the GitLab Runner executable. Might not be the same as the environment of the executor. +CI_RUNNER_ID Jobs only 8.10 0.5 The unique ID of the runner being used. +CI_RUNNER_REVISION Jobs only all 10.6 The revision of the runner running the job. +CI_RUNNER_SHORT_TOKEN Jobs only all 12.3 The runner’s unique ID, used to authenticate new job requests. In GitLab 14.9 and later, the token contains a prefix, and the first 17 characters are used. Prior to 14.9, the first eight characters are used. +CI_RUNNER_TAGS Jobs only 8.10 0.5 A comma-separated list of the runner tags. +CI_RUNNER_VERSION Jobs only all 10.6 The version of the GitLab Runner running the job. +CI_SERVER_HOST Pipeline 12.1 all The host of the GitLab instance URL, without protocol or port. For example gitlab.example.com. +CI_SERVER_NAME Pipeline all all The name of CI/CD server that coordinates jobs. +CI_SERVER_PORT Pipeline 12.8 all The port of the GitLab instance URL, without host or protocol. For example 8080. +CI_SERVER_PROTOCOL Pipeline 12.8 all The protocol of the GitLab instance URL, without host or port. For example https. +CI_SERVER_SHELL_SSH_HOST Pipeline 15.11 all The SSH host of the GitLab instance, used for access to Git repositories via SSH. For example gitlab.com. +CI_SERVER_SHELL_SSH_PORT Pipeline 15.11 all The SSH port of the GitLab instance, used for access to Git repositories via SSH. For example 22. +CI_SERVER_REVISION Pipeline all all GitLab revision that schedules jobs. +CI_SERVER_TLS_CA_FILE Pipeline all all File containing the TLS CA certificate to verify the GitLab server when tls-ca-file set in runner settings. +CI_SERVER_TLS_CERT_FILE Pipeline all all File containing the TLS certificate to verify the GitLab server when tls-cert-file set in runner settings. +CI_SERVER_TLS_KEY_FILE Pipeline all all File containing the TLS key to verify the GitLab server when tls-key-file set in runner settings. +CI_SERVER_URL Pipeline 12.7 all The base URL of the GitLab instance, including protocol and port. For example https://gitlab.example.com:8080. +CI_SERVER_VERSION_MAJOR Pipeline 11.4 all The major version of the GitLab instance. For example, if the GitLab version is 13.6.1, the CI_SERVER_VERSION_MAJOR is 13. +CI_SERVER_VERSION_MINOR Pipeline 11.4 all The minor version of the GitLab instance. For example, if the GitLab version is 13.6.1, the CI_SERVER_VERSION_MINOR is 6. +CI_SERVER_VERSION_PATCH Pipeline 11.4 all The patch version of the GitLab instance. For example, if the GitLab version is 13.6.1, the CI_SERVER_VERSION_PATCH is 1. +CI_SERVER_VERSION Pipeline all all The full version of the GitLab instance. +CI_SERVER Jobs only all all Available for all jobs executed in CI/CD. yes when available. +CI_SHARED_ENVIRONMENT Pipeline all 10.1 Only available if the job is executed in a shared environment (something that is persisted across CI/CD invocations, like the shell or ssh executor). true when available. +CI_TEMPLATE_REGISTRY_HOST Pipeline 15.3 all The host of the registry used by CI/CD templates. Defaults to registry.gitlab.com. +GITLAB_CI Pipeline all all Available for all jobs executed in CI/CD. true when available. +GITLAB_FEATURES Pipeline 10.6 all The comma-separated list of licensed features available for the GitLab instance and license. +GITLAB_USER_EMAIL Pipeline 8.12 all The email of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the email of the user who started the job. +GITLAB_USER_ID Pipeline 8.12 all The numeric ID of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the ID of the user who started the job. +GITLAB_USER_LOGIN Pipeline 10.0 all The username of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the username of the user who started the job. +GITLAB_USER_NAME Pipeline 10.0 all The display name of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the name of the user who started the job. +KUBECONFIG Pipeline 14.2 all The path to the kubeconfig file with contexts for every shared agent connection. Only available when a GitLab agent is authorized to access the project. +TRIGGER_PAYLOAD Pipeline 13.9 all The webhook payload. Only available when a pipeline is triggered with a webhook. diff --git a/ci/lib_gitlab_ci/predefined_vars.ml b/ci/lib_gitlab_ci/predefined_vars.ml new file mode 100644 index 0000000000000000000000000000000000000000..2ca17539ca5a0b64254f3d3804eeec815472ed75 --- /dev/null +++ b/ci/lib_gitlab_ci/predefined_vars.ml @@ -0,0 +1,318 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(* This file is generated. + + See [make_predefined_vars.sh] in this directory for more information. *) + +open Var + +let show = encode + +let chat_channel = make "CHAT_CHANNEL" + +let chat_input = make "CHAT_INPUT" + +let chat_user_id = make "CHAT_USER_ID" + +let ci = make "CI" + +let ci_api_v4_url = make "CI_API_V4_URL" + +let ci_api_graphql_url = make "CI_API_GRAPHQL_URL" + +let ci_builds_dir = make "CI_BUILDS_DIR" + +let ci_commit_author = make "CI_COMMIT_AUTHOR" + +let ci_commit_before_sha = make "CI_COMMIT_BEFORE_SHA" + +let ci_commit_branch = make "CI_COMMIT_BRANCH" + +let ci_commit_description = make "CI_COMMIT_DESCRIPTION" + +let ci_commit_message = make "CI_COMMIT_MESSAGE" + +let ci_commit_ref_name = make "CI_COMMIT_REF_NAME" + +let ci_commit_ref_protected = make "CI_COMMIT_REF_PROTECTED" + +let ci_commit_ref_slug = make "CI_COMMIT_REF_SLUG" + +let ci_commit_sha = make "CI_COMMIT_SHA" + +let ci_commit_short_sha = make "CI_COMMIT_SHORT_SHA" + +let ci_commit_tag = make "CI_COMMIT_TAG" + +let ci_commit_tag_message = make "CI_COMMIT_TAG_MESSAGE" + +let ci_commit_timestamp = make "CI_COMMIT_TIMESTAMP" + +let ci_commit_title = make "CI_COMMIT_TITLE" + +let ci_concurrent_id = make "CI_CONCURRENT_ID" + +let ci_concurrent_project_id = make "CI_CONCURRENT_PROJECT_ID" + +let ci_config_path = make "CI_CONFIG_PATH" + +let ci_debug_trace = make "CI_DEBUG_TRACE" + +let ci_debug_services = make "CI_DEBUG_SERVICES" + +let ci_default_branch = make "CI_DEFAULT_BRANCH" + +let ci_dependency_proxy_direct_group_image_prefix = + make "CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX" + +let ci_dependency_proxy_group_image_prefix = + make "CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX" + +let ci_dependency_proxy_password = make "CI_DEPENDENCY_PROXY_PASSWORD" + +let ci_dependency_proxy_server = make "CI_DEPENDENCY_PROXY_SERVER" + +let ci_dependency_proxy_user = make "CI_DEPENDENCY_PROXY_USER" + +let ci_deploy_freeze = make "CI_DEPLOY_FREEZE" + +let ci_deploy_password = make "CI_DEPLOY_PASSWORD" + +let ci_deploy_user = make "CI_DEPLOY_USER" + +let ci_disposable_environment = make "CI_DISPOSABLE_ENVIRONMENT" + +let ci_environment_name = make "CI_ENVIRONMENT_NAME" + +let ci_environment_slug = make "CI_ENVIRONMENT_SLUG" + +let ci_environment_url = make "CI_ENVIRONMENT_URL" + +let ci_environment_action = make "CI_ENVIRONMENT_ACTION" + +let ci_environment_tier = make "CI_ENVIRONMENT_TIER" + +let ci_release_description = make "CI_RELEASE_DESCRIPTION" + +let ci_gitlab_fips_mode = make "CI_GITLAB_FIPS_MODE" + +let ci_has_open_requirements = make "CI_HAS_OPEN_REQUIREMENTS" + +let ci_job_id = make "CI_JOB_ID" + +let ci_job_image = make "CI_JOB_IMAGE" + +let ci_job_manual = make "CI_JOB_MANUAL" + +let ci_job_name = make "CI_JOB_NAME" + +let ci_job_name_slug = make "CI_JOB_NAME_SLUG" + +let ci_job_stage = make "CI_JOB_STAGE" + +let ci_job_status = make "CI_JOB_STATUS" + +let ci_job_timeout = make "CI_JOB_TIMEOUT" + +let ci_job_token = make "CI_JOB_TOKEN" + +let ci_job_url = make "CI_JOB_URL" + +let ci_job_started_at = make "CI_JOB_STARTED_AT" + +let ci_kubernetes_active = make "CI_KUBERNETES_ACTIVE" + +let ci_node_index = make "CI_NODE_INDEX" + +let ci_node_total = make "CI_NODE_TOTAL" + +let ci_open_merge_requests = make "CI_OPEN_MERGE_REQUESTS" + +let ci_pages_domain = make "CI_PAGES_DOMAIN" + +let ci_pages_url = make "CI_PAGES_URL" + +let ci_pipeline_id = make "CI_PIPELINE_ID" + +let ci_pipeline_iid = make "CI_PIPELINE_IID" + +let ci_pipeline_source = make "CI_PIPELINE_SOURCE" + +let ci_pipeline_triggered = make "CI_PIPELINE_TRIGGERED" + +let ci_pipeline_url = make "CI_PIPELINE_URL" + +let ci_pipeline_created_at = make "CI_PIPELINE_CREATED_AT" + +let ci_pipeline_name = make "CI_PIPELINE_NAME" + +let ci_project_dir = make "CI_PROJECT_DIR" + +let ci_project_id = make "CI_PROJECT_ID" + +let ci_project_name = make "CI_PROJECT_NAME" + +let ci_project_namespace = make "CI_PROJECT_NAMESPACE" + +let ci_project_namespace_id = make "CI_PROJECT_NAMESPACE_ID" + +let ci_project_path_slug = make "CI_PROJECT_PATH_SLUG" + +let ci_project_path = make "CI_PROJECT_PATH" + +let ci_project_repository_languages = make "CI_PROJECT_REPOSITORY_LANGUAGES" + +let ci_project_root_namespace = make "CI_PROJECT_ROOT_NAMESPACE" + +let ci_project_title = make "CI_PROJECT_TITLE" + +let ci_project_description = make "CI_PROJECT_DESCRIPTION" + +let ci_project_url = make "CI_PROJECT_URL" + +let ci_project_visibility = make "CI_PROJECT_VISIBILITY" + +let ci_project_classification_label = make "CI_PROJECT_CLASSIFICATION_LABEL" + +let ci_registry = make "CI_REGISTRY" + +let ci_registry_image = make "CI_REGISTRY_IMAGE" + +let ci_registry_password = make "CI_REGISTRY_PASSWORD" + +let ci_registry_user = make "CI_REGISTRY_USER" + +let ci_repository_url = make "CI_REPOSITORY_URL" + +let ci_runner_description = make "CI_RUNNER_DESCRIPTION" + +let ci_runner_executable_arch = make "CI_RUNNER_EXECUTABLE_ARCH" + +let ci_runner_id = make "CI_RUNNER_ID" + +let ci_runner_revision = make "CI_RUNNER_REVISION" + +let ci_runner_short_token = make "CI_RUNNER_SHORT_TOKEN" + +let ci_runner_tags = make "CI_RUNNER_TAGS" + +let ci_runner_version = make "CI_RUNNER_VERSION" + +let ci_server_host = make "CI_SERVER_HOST" + +let ci_server_name = make "CI_SERVER_NAME" + +let ci_server_port = make "CI_SERVER_PORT" + +let ci_server_protocol = make "CI_SERVER_PROTOCOL" + +let ci_server_shell_ssh_host = make "CI_SERVER_SHELL_SSH_HOST" + +let ci_server_shell_ssh_port = make "CI_SERVER_SHELL_SSH_PORT" + +let ci_server_revision = make "CI_SERVER_REVISION" + +let ci_server_tls_ca_file = make "CI_SERVER_TLS_CA_FILE" + +let ci_server_tls_cert_file = make "CI_SERVER_TLS_CERT_FILE" + +let ci_server_tls_key_file = make "CI_SERVER_TLS_KEY_FILE" + +let ci_server_url = make "CI_SERVER_URL" + +let ci_server_version_major = make "CI_SERVER_VERSION_MAJOR" + +let ci_server_version_minor = make "CI_SERVER_VERSION_MINOR" + +let ci_server_version_patch = make "CI_SERVER_VERSION_PATCH" + +let ci_server_version = make "CI_SERVER_VERSION" + +let ci_server = make "CI_SERVER" + +let ci_shared_environment = make "CI_SHARED_ENVIRONMENT" + +let ci_template_registry_host = make "CI_TEMPLATE_REGISTRY_HOST" + +let gitlab_ci = make "GITLAB_CI" + +let gitlab_features = make "GITLAB_FEATURES" + +let gitlab_user_email = make "GITLAB_USER_EMAIL" + +let gitlab_user_id = make "GITLAB_USER_ID" + +let gitlab_user_login = make "GITLAB_USER_LOGIN" + +let gitlab_user_name = make "GITLAB_USER_NAME" + +let kubeconfig = make "KUBECONFIG" + +let trigger_payload = make "TRIGGER_PAYLOAD" + +let ci_merge_request_approved = make "CI_MERGE_REQUEST_APPROVED" + +let ci_merge_request_assignees = make "CI_MERGE_REQUEST_ASSIGNEES" + +let ci_merge_request_diff_base_sha = make "CI_MERGE_REQUEST_DIFF_BASE_SHA" + +let ci_merge_request_diff_id = make "CI_MERGE_REQUEST_DIFF_ID" + +let ci_merge_request_event_type = make "CI_MERGE_REQUEST_EVENT_TYPE" + +let ci_merge_request_description = make "CI_MERGE_REQUEST_DESCRIPTION" + +let ci_merge_request_description_is_truncated = + make "CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED" + +let ci_merge_request_id = make "CI_MERGE_REQUEST_ID" + +let ci_merge_request_iid = make "CI_MERGE_REQUEST_IID" + +let ci_merge_request_labels = make "CI_MERGE_REQUEST_LABELS" + +let ci_merge_request_milestone = make "CI_MERGE_REQUEST_MILESTONE" + +let ci_merge_request_project_id = make "CI_MERGE_REQUEST_PROJECT_ID" + +let ci_merge_request_project_path = make "CI_MERGE_REQUEST_PROJECT_PATH" + +let ci_merge_request_project_url = make "CI_MERGE_REQUEST_PROJECT_URL" + +let ci_merge_request_ref_path = make "CI_MERGE_REQUEST_REF_PATH" + +let ci_merge_request_source_branch_name = + make "CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" + +let ci_merge_request_source_branch_protected = + make "CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED" + +let ci_merge_request_source_branch_sha = + make "CI_MERGE_REQUEST_SOURCE_BRANCH_SHA" + +let ci_merge_request_source_project_id = + make "CI_MERGE_REQUEST_SOURCE_PROJECT_ID" + +let ci_merge_request_source_project_path = + make "CI_MERGE_REQUEST_SOURCE_PROJECT_PATH" + +let ci_merge_request_source_project_url = + make "CI_MERGE_REQUEST_SOURCE_PROJECT_URL" + +let ci_merge_request_squash_on_merge = make "CI_MERGE_REQUEST_SQUASH_ON_MERGE" + +let ci_merge_request_target_branch_name = + make "CI_MERGE_REQUEST_TARGET_BRANCH_NAME" + +let ci_merge_request_target_branch_protected = + make "CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED" + +let ci_merge_request_target_branch_sha = + make "CI_MERGE_REQUEST_TARGET_BRANCH_SHA" + +let ci_merge_request_title = make "CI_MERGE_REQUEST_TITLE" diff --git a/ci/lib_gitlab_ci/predefined_vars.mli b/ci/lib_gitlab_ci/predefined_vars.mli new file mode 100644 index 0000000000000000000000000000000000000000..cf06d229853eeadfd72e8ac163efaf7505315dfe --- /dev/null +++ b/ci/lib_gitlab_ci/predefined_vars.mli @@ -0,0 +1,1300 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** Predefined CI/CD variables in all pipelines. + + This contains a subset of the + {{:https://docs.gitlab.com/ee/ci/variables/predefined_variables.html} + predefined variables}. *) + +(** String representation of a variable with the sigil-sign. + + A handy alias of {!Var.encode}. *) +val show : Var.t -> string + +(** Corresponds to [CHAT_CHANNEL]. + + The Source chat channel that triggered the ChatOps command. + + Context: [Pipeline]. Available since GitLab [10.6]. + Available in [all] runners. *) +val chat_channel : Var.t + +(** Corresponds to [CHAT_INPUT]. + + The additional arguments passed with the ChatOps command. + + Context: [Pipeline]. Available since GitLab [10.6]. + Available in [all] runners. *) +val chat_input : Var.t + +(** Corresponds to [CHAT_USER_ID]. + + The chat service’s user ID of the user who triggered the ChatOps command. + + Context: [Pipeline]. Available since GitLab [14.4]. + Available in [all] runners. *) +val chat_user_id : Var.t + +(** Corresponds to [CI]. + + Available for all jobs executed in CI/CD. ["true"] when available. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [0.4] runners. *) +val ci : Var.t + +(** Corresponds to [CI_API_V4_URL]. + + The GitLab API v4 root URL. + + Context: [Pipeline]. Available since GitLab [11.7]. + Available in [all] runners. *) +val ci_api_v4_url : Var.t + +(** Corresponds to [CI_API_GRAPHQL_URL]. + + The GitLab API GraphQL root URL. + + Context: [Pipeline]. Available since GitLab [15.11]. + Available in [all] runners. *) +val ci_api_graphql_url : Var.t + +(** Corresponds to [CI_BUILDS_DIR]. + + The top-level directory where builds are executed. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [11.10] runners. *) +val ci_builds_dir : Var.t + +(** Corresponds to [CI_COMMIT_AUTHOR]. + + The author of the commit in Name format. + + Context: [Pipeline]. Available since GitLab [13.11]. + Available in [all] runners. *) +val ci_commit_author : Var.t + +(** Corresponds to [CI_COMMIT_BEFORE_SHA]. + + The previous latest commit present on a branch or tag. Is always + 0000000000000000000000000000000000000000 for merge request pipelines, the + first commit in pipelines for branches or tags, or when manually running a + pipeline. + + Context: [Pipeline]. Available since GitLab [11.2]. + Available in [all] runners. *) +val ci_commit_before_sha : Var.t + +(** Corresponds to [CI_COMMIT_BRANCH]. + + The commit branch name. Available in branch pipelines, including pipelines + for the default branch. Not available in merge request pipelines or tag + pipelines. + + Context: [Pipeline]. Available since GitLab [12.6]. + Available in [0.5] runners. *) +val ci_commit_branch : Var.t + +(** Corresponds to [CI_COMMIT_DESCRIPTION]. + + The description of the commit. If the title is shorter than 100 characters, + the message without the first line. + + Context: [Pipeline]. Available since GitLab [10.8]. + Available in [all] runners. *) +val ci_commit_description : Var.t + +(** Corresponds to [CI_COMMIT_MESSAGE]. + + The full commit message. + + Context: [Pipeline]. Available since GitLab [10.8]. + Available in [all] runners. *) +val ci_commit_message : Var.t + +(** Corresponds to [CI_COMMIT_REF_NAME]. + + The branch or tag name for which project is built. + + Context: [Pipeline]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_commit_ref_name : Var.t + +(** Corresponds to [CI_COMMIT_REF_PROTECTED]. + + ["true"] if the job is running for a protected reference, ["false"] otherwise. + + Context: [Pipeline]. Available since GitLab [11.11]. + Available in [all] runners. *) +val ci_commit_ref_protected : Var.t + +(** Corresponds to [CI_COMMIT_REF_SLUG]. + + CI_COMMIT_REF_NAME in lowercase, shortened to 63 bytes, and with everything + except 0-9 and a-z replaced with -. No leading / trailing -. Use in URLs, + host names and domain names. + + Context: [Pipeline]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_commit_ref_slug : Var.t + +(** Corresponds to [CI_COMMIT_SHA]. + + The commit revision the project is built for. + + Context: [Pipeline]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_commit_sha : Var.t + +(** Corresponds to [CI_COMMIT_SHORT_SHA]. + + The first eight characters of CI_COMMIT_SHA. + + Context: [Pipeline]. Available since GitLab [11.7]. + Available in [all] runners. *) +val ci_commit_short_sha : Var.t + +(** Corresponds to [CI_COMMIT_TAG]. + + The commit tag name. Available only in pipelines for tags. + + Context: [Pipeline]. Available since GitLab [9.0]. + Available in [0.5] runners. *) +val ci_commit_tag : Var.t + +(** Corresponds to [CI_COMMIT_TAG_MESSAGE]. + + The commit tag message. Available only in pipelines for tags. + + Context: [Pipeline]. Available since GitLab [15.5]. + Available in [all] runners. *) +val ci_commit_tag_message : Var.t + +(** Corresponds to [CI_COMMIT_TIMESTAMP]. + + The timestamp of the commit in the ISO 8601 format. For example, + 2022-01-31T16:47:55Z. + + Context: [Pipeline]. Available since GitLab [13.4]. + Available in [all] runners. *) +val ci_commit_timestamp : Var.t + +(** Corresponds to [CI_COMMIT_TITLE]. + + The title of the commit. The full first line of the message. + + Context: [Pipeline]. Available since GitLab [10.8]. + Available in [all] runners. *) +val ci_commit_title : Var.t + +(** Corresponds to [CI_CONCURRENT_ID]. + + The unique ID of build execution in a single executor. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [11.10] runners. *) +val ci_concurrent_id : Var.t + +(** Corresponds to [CI_CONCURRENT_PROJECT_ID]. + + The unique ID of build execution in a single executor and project. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [11.10] runners. *) +val ci_concurrent_project_id : Var.t + +(** Corresponds to [CI_CONFIG_PATH]. + + The path to the CI/CD configuration file. Defaults to .gitlab-ci.yml. + Read-only inside a running pipeline. + + Context: [Pipeline]. Available since GitLab [9.4]. + Available in [0.5] runners. *) +val ci_config_path : Var.t + +(** Corresponds to [CI_DEBUG_TRACE]. + + ["true"] if debug logging (tracing) is enabled. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [1.7] runners. *) +val ci_debug_trace : Var.t + +(** Corresponds to [CI_DEBUG_SERVICES]. + + ["true"] if service container logging is enabled. + + Context: [Pipeline]. Available since GitLab [15.7]. + Available in [15.7] runners. *) +val ci_debug_services : Var.t + +(** Corresponds to [CI_DEFAULT_BRANCH]. + + The name of the project’s default branch. + + Context: [Pipeline]. Available since GitLab [12.4]. + Available in [all] runners. *) +val ci_default_branch : Var.t + +(** Corresponds to [CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX]. + + The direct group image prefix for pulling images through the Dependency + Proxy. + + Context: [Pipeline]. Available since GitLab [14.3]. + Available in [all] runners. *) +val ci_dependency_proxy_direct_group_image_prefix : Var.t + +(** Corresponds to [CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX]. + + The top-level group image prefix for pulling images through the Dependency + Proxy. + + Context: [Pipeline]. Available since GitLab [13.7]. + Available in [all] runners. *) +val ci_dependency_proxy_group_image_prefix : Var.t + +(** Corresponds to [CI_DEPENDENCY_PROXY_PASSWORD]. + + The password to pull images through the Dependency Proxy. + + Context: [Pipeline]. Available since GitLab [13.7]. + Available in [all] runners. *) +val ci_dependency_proxy_password : Var.t + +(** Corresponds to [CI_DEPENDENCY_PROXY_SERVER]. + + The server for logging in to the Dependency Proxy. This is equivalent to + $CI_SERVER_HOST:$CI_SERVER_PORT. + + Context: [Pipeline]. Available since GitLab [13.7]. + Available in [all] runners. *) +val ci_dependency_proxy_server : Var.t + +(** Corresponds to [CI_DEPENDENCY_PROXY_USER]. + + The username to pull images through the Dependency Proxy. + + Context: [Pipeline]. Available since GitLab [13.7]. + Available in [all] runners. *) +val ci_dependency_proxy_user : Var.t + +(** Corresponds to [CI_DEPLOY_FREEZE]. + + Only available if the pipeline runs during a deploy freeze window. ["true"] + when available. + + Context: [Pipeline]. Available since GitLab [13.2]. + Available in [all] runners. *) +val ci_deploy_freeze : Var.t + +(** Corresponds to [CI_DEPLOY_PASSWORD]. + + The authentication password of the GitLab Deploy Token, if the project has + one. + + Context: [Jobs only]. Available since GitLab [10.8]. + Available in [all] runners. *) +val ci_deploy_password : Var.t + +(** Corresponds to [CI_DEPLOY_USER]. + + The authentication username of the GitLab Deploy Token, if the project has + one. + + Context: [Jobs only]. Available since GitLab [10.8]. + Available in [all] runners. *) +val ci_deploy_user : Var.t + +(** Corresponds to [CI_DISPOSABLE_ENVIRONMENT]. + + Only available if the job is executed in a disposable environment + (something that is created only for this job and disposed of/destroyed + after the execution - all executors except shell and ssh). ["true"] when + available. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [10.1] runners. *) +val ci_disposable_environment : Var.t + +(** Corresponds to [CI_ENVIRONMENT_NAME]. + + The name of the environment for this job. Available if environment:name is + set. + + Context: [Pipeline]. Available since GitLab [8.15]. + Available in [all] runners. *) +val ci_environment_name : Var.t + +(** Corresponds to [CI_ENVIRONMENT_SLUG]. + + The simplified version of the environment name, suitable for inclusion in + DNS, URLs, Kubernetes labels, and so on. Available if environment:name is + set. The slug is truncated to 24 characters. A random suffix is + automatically added to uppercase environment names. + + Context: [Pipeline]. Available since GitLab [8.15]. + Available in [all] runners. *) +val ci_environment_slug : Var.t + +(** Corresponds to [CI_ENVIRONMENT_URL]. + + The URL of the environment for this job. Available if environment:url is + set. + + Context: [Pipeline]. Available since GitLab [9.3]. + Available in [all] runners. *) +val ci_environment_url : Var.t + +(** Corresponds to [CI_ENVIRONMENT_ACTION]. + + The action annotation specified for this job’s environment. Available if + environment:action is set. Can be start, prepare, or stop. + + Context: [Pipeline]. Available since GitLab [13.11]. + Available in [all] runners. *) +val ci_environment_action : Var.t + +(** Corresponds to [CI_ENVIRONMENT_TIER]. + + The deployment tier of the environment for this job. + + Context: [Pipeline]. Available since GitLab [14.0]. + Available in [all] runners. *) +val ci_environment_tier : Var.t + +(** Corresponds to [CI_RELEASE_DESCRIPTION]. + + The description of the release. Available only on pipelines for tags. + Description length is limited to first 1024 characters. + + Context: [Pipeline]. Available since GitLab [15.5]. + Available in [all] runners. *) +val ci_release_description : Var.t + +(** Corresponds to [CI_GITLAB_FIPS_MODE]. + + Only available if FIPS mode is enabled in the GitLab instance. ["true"] when + available. + + Context: [Pipeline]. Available since GitLab [14.10]. + Available in [all] runners. *) +val ci_gitlab_fips_mode : Var.t + +(** Corresponds to [CI_HAS_OPEN_REQUIREMENTS]. + + Only available if the pipeline’s project has an open requirement. ["true"] + when available. + + Context: [Pipeline]. Available since GitLab [13.1]. + Available in [all] runners. *) +val ci_has_open_requirements : Var.t + +(** Corresponds to [CI_JOB_ID]. + + The internal ID of the job, unique across all jobs in the GitLab instance. + + Context: [Jobs only]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_job_id : Var.t + +(** Corresponds to [CI_JOB_IMAGE]. + + The name of the Docker image running the job. + + Context: [Pipeline]. Available since GitLab [12.9]. + Available in [12.9] runners. *) +val ci_job_image : Var.t + +(** Corresponds to [CI_JOB_MANUAL]. + + Only available if the job was started manually. ["true"] when available. + + Context: [Pipeline]. Available since GitLab [8.12]. + Available in [all] runners. *) +val ci_job_manual : Var.t + +(** Corresponds to [CI_JOB_NAME]. + + The name of the job. + + Context: [Pipeline]. Available since GitLab [9.0]. + Available in [0.5] runners. *) +val ci_job_name : Var.t + +(** Corresponds to [CI_JOB_NAME_SLUG]. + + CI_JOB_NAME in lowercase, shortened to 63 bytes, and with everything except + 0-9 and a-z replaced with -. No leading / trailing -. Use in paths. + + Context: [Pipeline]. Available since GitLab [15.4]. + Available in [all] runners. *) +val ci_job_name_slug : Var.t + +(** Corresponds to [CI_JOB_STAGE]. + + The name of the job’s stage. + + Context: [Pipeline]. Available since GitLab [9.0]. + Available in [0.5] runners. *) +val ci_job_stage : Var.t + +(** Corresponds to [CI_JOB_STATUS]. + + The status of the job as each runner stage is executed. Use with + after_script. Can be success, failed, or canceled. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [13.5] runners. *) +val ci_job_status : Var.t + +(** Corresponds to [CI_JOB_TIMEOUT]. + + The job timeout, in seconds. + + Context: [Jobs only]. Available since GitLab [15.7]. + Available in [15.7] runners. *) +val ci_job_timeout : Var.t + +(** Corresponds to [CI_JOB_TOKEN]. + + A token to authenticate with certain API endpoints. The token is valid as + long as the job is running. + + Context: [Jobs only]. Available since GitLab [9.0]. + Available in [1.2] runners. *) +val ci_job_token : Var.t + +(** Corresponds to [CI_JOB_URL]. + + The job details URL. + + Context: [Jobs only]. Available since GitLab [11.1]. + Available in [0.5] runners. *) +val ci_job_url : Var.t + +(** Corresponds to [CI_JOB_STARTED_AT]. + + The UTC datetime when a job started, in ISO 8601 format. For example, + 2022-01-31T16:47:55Z. + + Context: [Jobs only]. Available since GitLab [13.10]. + Available in [all] runners. *) +val ci_job_started_at : Var.t + +(** Corresponds to [CI_KUBERNETES_ACTIVE]. + + Only available if the pipeline has a Kubernetes cluster available for + deployments. ["true"] when available. + + Context: [Pipeline]. Available since GitLab [13.0]. + Available in [all] runners. *) +val ci_kubernetes_active : Var.t + +(** Corresponds to [CI_NODE_INDEX]. + + The index of the job in the job set. Only available if the job uses + parallel. + + Context: [Pipeline]. Available since GitLab [11.5]. + Available in [all] runners. *) +val ci_node_index : Var.t + +(** Corresponds to [CI_NODE_TOTAL]. + + The total number of instances of this job running in parallel. Set to 1 if + the job does not use parallel. + + Context: [Pipeline]. Available since GitLab [11.5]. + Available in [all] runners. *) +val ci_node_total : Var.t + +(** Corresponds to [CI_OPEN_MERGE_REQUESTS]. + + A comma-separated list of up to four merge requests that use the current + branch and project as the merge request source. Only available in branch + and merge request pipelines if the branch has an associated merge request. + For example, gitlab-org/gitlab!333,gitlab-org/gitlab-foss!11. + + Context: [Pipeline]. Available since GitLab [13.8]. + Available in [all] runners. *) +val ci_open_merge_requests : Var.t + +(** Corresponds to [CI_PAGES_DOMAIN]. + + The configured domain that hosts GitLab Pages. + + Context: [Pipeline]. Available since GitLab [11.8]. + Available in [all] runners. *) +val ci_pages_domain : Var.t + +(** Corresponds to [CI_PAGES_URL]. + + The URL for a GitLab Pages site. Always a subdomain of CI_PAGES_DOMAIN. + + Context: [Pipeline]. Available since GitLab [11.8]. + Available in [all] runners. *) +val ci_pages_url : Var.t + +(** Corresponds to [CI_PIPELINE_ID]. + + The instance-level ID of the current pipeline. This ID is unique across all + projects on the GitLab instance. + + Context: [Jobs only]. Available since GitLab [8.10]. + Available in [all] runners. *) +val ci_pipeline_id : Var.t + +(** Corresponds to [CI_PIPELINE_IID]. + + The project-level IID (internal ID) of the current pipeline. This ID is + unique only within the current project. + + Context: [Pipeline]. Available since GitLab [11.0]. + Available in [all] runners. *) +val ci_pipeline_iid : Var.t + +(** Corresponds to [CI_PIPELINE_SOURCE]. + + How the pipeline was triggered. Can be push, web, schedule, api, external, + chat, webide, merge_request_event, external_pull_request_event, + parent_pipeline, trigger, or pipeline. For a description of each value, see + Common if clauses for rules, which uses this variable to control when jobs + run. + + Context: [Pipeline]. Available since GitLab [10.0]. + Available in [all] runners. *) +val ci_pipeline_source : Var.t + +(** Corresponds to [CI_PIPELINE_TRIGGERED]. + + ["true"] if the job was triggered. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_pipeline_triggered : Var.t + +(** Corresponds to [CI_PIPELINE_URL]. + + The URL for the pipeline details. + + Context: [Jobs only]. Available since GitLab [11.1]. + Available in [0.5] runners. *) +val ci_pipeline_url : Var.t + +(** Corresponds to [CI_PIPELINE_CREATED_AT]. + + The UTC datetime when the pipeline was created, in ISO 8601 format. For + example, 2022-01-31T16:47:55Z. + + Context: [Pipeline]. Available since GitLab [13.10]. + Available in [all] runners. *) +val ci_pipeline_created_at : Var.t + +(** Corresponds to [CI_PIPELINE_NAME]. + + The pipeline name defined in workflow:name + + Context: [Pipeline]. Available since GitLab [16.3]. + Available in [all] runners. *) +val ci_pipeline_name : Var.t + +(** Corresponds to [CI_PROJECT_DIR]. + + The full path the repository is cloned to, and where the job runs from. If + the GitLab Runner builds_dir parameter is set, this variable is set + relative to the value of builds_dir. For more information, see the Advanced + GitLab Runner configuration. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_project_dir : Var.t + +(** Corresponds to [CI_PROJECT_ID]. + + The ID of the current project. This ID is unique across all projects on the + GitLab instance. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_project_id : Var.t + +(** Corresponds to [CI_PROJECT_NAME]. + + The name of the directory for the project. For example if the project URL + is gitlab.example.com/group-name/project-1, CI_PROJECT_NAME is project-1. + + Context: [Pipeline]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_project_name : Var.t + +(** Corresponds to [CI_PROJECT_NAMESPACE]. + + The project namespace (username or group name) of the job. + + Context: [Pipeline]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_project_namespace : Var.t + +(** Corresponds to [CI_PROJECT_NAMESPACE_ID]. + + The project namespace ID of the job. + + Context: [Pipeline]. Available since GitLab [15.7]. + Available in [0.5] runners. *) +val ci_project_namespace_id : Var.t + +(** Corresponds to [CI_PROJECT_PATH_SLUG]. + + $CI_PROJECT_PATH in lowercase with characters that are not a-z or 0-9 + replaced with - and shortened to 63 bytes. Use in URLs and domain names. + + Context: [Pipeline]. Available since GitLab [9.3]. + Available in [all] runners. *) +val ci_project_path_slug : Var.t + +(** Corresponds to [CI_PROJECT_PATH]. + + The project namespace with the project name included. + + Context: [Pipeline]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_project_path : Var.t + +(** Corresponds to [CI_PROJECT_REPOSITORY_LANGUAGES]. + + A comma-separated, lowercase list of the languages used in the repository. + For example ruby,javascript,html,css. The maximum number of languages is + limited to 5. An issue proposes to increase the limit. + + Context: [Pipeline]. Available since GitLab [12.3]. + Available in [all] runners. *) +val ci_project_repository_languages : Var.t + +(** Corresponds to [CI_PROJECT_ROOT_NAMESPACE]. + + The root project namespace (username or group name) of the job. For + example, if CI_PROJECT_NAMESPACE is + root-group/child-group/grandchild-group, CI_PROJECT_ROOT_NAMESPACE is + root-group. + + Context: [Pipeline]. Available since GitLab [13.2]. + Available in [0.5] runners. *) +val ci_project_root_namespace : Var.t + +(** Corresponds to [CI_PROJECT_TITLE]. + + The human-readable project name as displayed in the GitLab web interface. + + Context: [Pipeline]. Available since GitLab [12.4]. + Available in [all] runners. *) +val ci_project_title : Var.t + +(** Corresponds to [CI_PROJECT_DESCRIPTION]. + + The project description as displayed in the GitLab web interface. + + Context: [Pipeline]. Available since GitLab [15.1]. + Available in [all] runners. *) +val ci_project_description : Var.t + +(** Corresponds to [CI_PROJECT_URL]. + + The HTTP(S) address of the project. + + Context: [Pipeline]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_project_url : Var.t + +(** Corresponds to [CI_PROJECT_VISIBILITY]. + + The project visibility. Can be internal, private, or public. + + Context: [Pipeline]. Available since GitLab [10.3]. + Available in [all] runners. *) +val ci_project_visibility : Var.t + +(** Corresponds to [CI_PROJECT_CLASSIFICATION_LABEL]. + + The project external authorization classification label. + + Context: [Pipeline]. Available since GitLab [14.2]. + Available in [all] runners. *) +val ci_project_classification_label : Var.t + +(** Corresponds to [CI_REGISTRY]. + + Address of the container registry server, formatted as [:]. For + example: registry.gitlab.example.com. Only available if the container + registry is enabled for the GitLab instance. + + Context: [Pipeline]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_registry : Var.t + +(** Corresponds to [CI_REGISTRY_IMAGE]. + + Base address for the container registry to push, pull, or tag project’s + images, formatted as [:]/. For example: + registry.gitlab.example.com/my_group/my_project. Image names must follow + the container registry naming convention. Only available if the container + registry is enabled for the project. + + Context: [Pipeline]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_registry_image : Var.t + +(** Corresponds to [CI_REGISTRY_PASSWORD]. + + The password to push containers to the GitLab project’s container + registry. Only available if the container registry is enabled for the + project. This password value is the same as the CI_JOB_TOKEN and is valid + only as long as the job is running. Use the CI_DEPLOY_PASSWORD for + long-lived access to the registry + + Context: [Jobs only]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_registry_password : Var.t + +(** Corresponds to [CI_REGISTRY_USER]. + + The username to push containers to the project’s GitLab container + registry. Only available if the container registry is enabled for the + project. + + Context: [Jobs only]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_registry_user : Var.t + +(** Corresponds to [CI_REPOSITORY_URL]. + + The full path to Git clone (HTTP) the repository with a CI/CD job token, in + the format + https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.example.com/my-group/my-project + .git. + + Context: [Jobs only]. Available since GitLab [9.0]. + Available in [all] runners. *) +val ci_repository_url : Var.t + +(** Corresponds to [CI_RUNNER_DESCRIPTION]. + + The description of the runner. + + Context: [Jobs only]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_runner_description : Var.t + +(** Corresponds to [CI_RUNNER_EXECUTABLE_ARCH]. + + The OS/architecture of the GitLab Runner executable. Might not be the same + as the environment of the executor. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [10.6] runners. *) +val ci_runner_executable_arch : Var.t + +(** Corresponds to [CI_RUNNER_ID]. + + The unique ID of the runner being used. + + Context: [Jobs only]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_runner_id : Var.t + +(** Corresponds to [CI_RUNNER_REVISION]. + + The revision of the runner running the job. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [10.6] runners. *) +val ci_runner_revision : Var.t + +(** Corresponds to [CI_RUNNER_SHORT_TOKEN]. + + The runner’s unique ID, used to authenticate new job requests. In GitLab + 14.9 and later, the token contains a prefix, and the first 17 characters + are used. Prior to 14.9, the first eight characters are used. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [12.3] runners. *) +val ci_runner_short_token : Var.t + +(** Corresponds to [CI_RUNNER_TAGS]. + + A comma-separated list of the runner tags. + + Context: [Jobs only]. Available since GitLab [8.10]. + Available in [0.5] runners. *) +val ci_runner_tags : Var.t + +(** Corresponds to [CI_RUNNER_VERSION]. + + The version of the GitLab Runner running the job. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [10.6] runners. *) +val ci_runner_version : Var.t + +(** Corresponds to [CI_SERVER_HOST]. + + The host of the GitLab instance URL, without protocol or port. For example + gitlab.example.com. + + Context: [Pipeline]. Available since GitLab [12.1]. + Available in [all] runners. *) +val ci_server_host : Var.t + +(** Corresponds to [CI_SERVER_NAME]. + + The name of CI/CD server that coordinates jobs. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server_name : Var.t + +(** Corresponds to [CI_SERVER_PORT]. + + The port of the GitLab instance URL, without host or protocol. For example + 8080. + + Context: [Pipeline]. Available since GitLab [12.8]. + Available in [all] runners. *) +val ci_server_port : Var.t + +(** Corresponds to [CI_SERVER_PROTOCOL]. + + The protocol of the GitLab instance URL, without host or port. For example + https. + + Context: [Pipeline]. Available since GitLab [12.8]. + Available in [all] runners. *) +val ci_server_protocol : Var.t + +(** Corresponds to [CI_SERVER_SHELL_SSH_HOST]. + + The SSH host of the GitLab instance, used for access to Git repositories + via SSH. For example gitlab.com. + + Context: [Pipeline]. Available since GitLab [15.11]. + Available in [all] runners. *) +val ci_server_shell_ssh_host : Var.t + +(** Corresponds to [CI_SERVER_SHELL_SSH_PORT]. + + The SSH port of the GitLab instance, used for access to Git repositories + via SSH. For example 22. + + Context: [Pipeline]. Available since GitLab [15.11]. + Available in [all] runners. *) +val ci_server_shell_ssh_port : Var.t + +(** Corresponds to [CI_SERVER_REVISION]. + + GitLab revision that schedules jobs. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server_revision : Var.t + +(** Corresponds to [CI_SERVER_TLS_CA_FILE]. + + File containing the TLS CA certificate to verify the GitLab server when + tls-ca-file set in runner settings. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server_tls_ca_file : Var.t + +(** Corresponds to [CI_SERVER_TLS_CERT_FILE]. + + File containing the TLS certificate to verify the GitLab server when + tls-cert-file set in runner settings. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server_tls_cert_file : Var.t + +(** Corresponds to [CI_SERVER_TLS_KEY_FILE]. + + File containing the TLS key to verify the GitLab server when tls-key-file + set in runner settings. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server_tls_key_file : Var.t + +(** Corresponds to [CI_SERVER_URL]. + + The base URL of the GitLab instance, including protocol and port. For + example https://gitlab.example.com:8080. + + Context: [Pipeline]. Available since GitLab [12.7]. + Available in [all] runners. *) +val ci_server_url : Var.t + +(** Corresponds to [CI_SERVER_VERSION_MAJOR]. + + The major version of the GitLab instance. For example, if the GitLab + version is 13.6.1, the CI_SERVER_VERSION_MAJOR is 13. + + Context: [Pipeline]. Available since GitLab [11.4]. + Available in [all] runners. *) +val ci_server_version_major : Var.t + +(** Corresponds to [CI_SERVER_VERSION_MINOR]. + + The minor version of the GitLab instance. For example, if the GitLab + version is 13.6.1, the CI_SERVER_VERSION_MINOR is 6. + + Context: [Pipeline]. Available since GitLab [11.4]. + Available in [all] runners. *) +val ci_server_version_minor : Var.t + +(** Corresponds to [CI_SERVER_VERSION_PATCH]. + + The patch version of the GitLab instance. For example, if the GitLab + version is 13.6.1, the CI_SERVER_VERSION_PATCH is 1. + + Context: [Pipeline]. Available since GitLab [11.4]. + Available in [all] runners. *) +val ci_server_version_patch : Var.t + +(** Corresponds to [CI_SERVER_VERSION]. + + The full version of the GitLab instance. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server_version : Var.t + +(** Corresponds to [CI_SERVER]. + + Available for all jobs executed in CI/CD. yes when available. + + Context: [Jobs only]. Available since GitLab [all]. + Available in [all] runners. *) +val ci_server : Var.t + +(** Corresponds to [CI_SHARED_ENVIRONMENT]. + + Only available if the job is executed in a shared environment (something + that is persisted across CI/CD invocations, like the shell or ssh + executor). ["true"] when available. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [10.1] runners. *) +val ci_shared_environment : Var.t + +(** Corresponds to [CI_TEMPLATE_REGISTRY_HOST]. + + The host of the registry used by CI/CD templates. Defaults to + registry.gitlab.com. + + Context: [Pipeline]. Available since GitLab [15.3]. + Available in [all] runners. *) +val ci_template_registry_host : Var.t + +(** Corresponds to [GITLAB_CI]. + + Available for all jobs executed in CI/CD. ["true"] when available. + + Context: [Pipeline]. Available since GitLab [all]. + Available in [all] runners. *) +val gitlab_ci : Var.t + +(** Corresponds to [GITLAB_FEATURES]. + + The comma-separated list of licensed features available for the GitLab + instance and license. + + Context: [Pipeline]. Available since GitLab [10.6]. + Available in [all] runners. *) +val gitlab_features : Var.t + +(** Corresponds to [GITLAB_USER_EMAIL]. + + The email of the user who started the pipeline, unless the job is a manual + job. In manual jobs, the value is the email of the user who started the job. + + Context: [Pipeline]. Available since GitLab [8.12]. + Available in [all] runners. *) +val gitlab_user_email : Var.t + +(** Corresponds to [GITLAB_USER_ID]. + + The numeric ID of the user who started the pipeline, unless the job is a + manual job. In manual jobs, the value is the ID of the user who started the + job. + + Context: [Pipeline]. Available since GitLab [8.12]. + Available in [all] runners. *) +val gitlab_user_id : Var.t + +(** Corresponds to [GITLAB_USER_LOGIN]. + + The username of the user who started the pipeline, unless the job is a + manual job. In manual jobs, the value is the username of the user who + started the job. + + Context: [Pipeline]. Available since GitLab [10.0]. + Available in [all] runners. *) +val gitlab_user_login : Var.t + +(** Corresponds to [GITLAB_USER_NAME]. + + The display name of the user who started the pipeline, unless the job is a + manual job. In manual jobs, the value is the name of the user who started + the job. + + Context: [Pipeline]. Available since GitLab [10.0]. + Available in [all] runners. *) +val gitlab_user_name : Var.t + +(** Corresponds to [KUBECONFIG]. + + The path to the kubeconfig file with contexts for every shared agent + connection. Only available when a GitLab agent is authorized to access the + project. + + Context: [Pipeline]. Available since GitLab [14.2]. + Available in [all] runners. *) +val kubeconfig : Var.t + +(** Corresponds to [TRIGGER_PAYLOAD]. + + The webhook payload. Only available when a pipeline is triggered with a + webhook. + + Context: [Pipeline]. Available since GitLab [13.9]. + Available in [all] runners. *) +val trigger_payload : Var.t + +(** {2 Predefined variables for merge request pipelines} *) + +(** Corresponds to [CI_MERGE_REQUEST_APPROVED]. + + Approval status of the merge request. ["true"] when merge request approvals is + available and the merge request has been approved. + + Context: merge requests. Available since GitLab [14.1]. + Available in [all] runners. *) +val ci_merge_request_approved : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_ASSIGNEES]. + + Comma-separated list of usernames of assignees for the merge request. + + Context: merge requests. Available since GitLab [11.9]. + Available in [all] runners. *) +val ci_merge_request_assignees : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_DIFF_BASE_SHA]. + + The base SHA of the merge request diff. + + Context: merge requests. Available since GitLab [13.7]. + Available in [all] runners. *) +val ci_merge_request_diff_base_sha : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_DIFF_ID]. + + The version of the merge request diff. + + Context: merge requests. Available since GitLab [13.7]. + Available in [all] runners. *) +val ci_merge_request_diff_id : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_EVENT_TYPE]. + + The event type of the merge request. Can be detached, merged_result or + merge_train. + + Context: merge requests. Available since GitLab [12.3]. + Available in [all] runners. *) +val ci_merge_request_event_type : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_DESCRIPTION]. + + The description of the merge request. If the description is more than 2700 + characters long, only the first 2700 characters are stored in the variable. + + Context: merge requests. Available since GitLab [16.7]. + Available in [all] runners. *) +val ci_merge_request_description : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED]. + + ["true"] if CI_MERGE_REQUEST_DESCRIPTION is truncated down to 2700 characters + because the description of the merge request is too long. + + Context: merge requests. Available since GitLab [16.8]. + Available in [all] runners. *) +val ci_merge_request_description_is_truncated : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_ID]. + + The instance-level ID of the merge request. This is a unique ID across all + projects on the GitLab instance. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_id : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_IID]. + + The project-level IID (internal ID) of the merge request. This ID is unique + for the current project, and is the number used in the merge request URL, + page title, and other visible locations. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_iid : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_LABELS]. + + Comma-separated label names of the merge request. + + Context: merge requests. Available since GitLab [11.9]. + Available in [all] runners. *) +val ci_merge_request_labels : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_MILESTONE]. + + The milestone title of the merge request. + + Context: merge requests. Available since GitLab [11.9]. + Available in [all] runners. *) +val ci_merge_request_milestone : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_PROJECT_ID]. + + The ID of the project of the merge request. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_project_id : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_PROJECT_PATH]. + + The path of the project of the merge request. For example + namespace/awesome-project. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_project_path : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_PROJECT_URL]. + + The URL of the project of the merge request. For example, + http://192.168.10.15:3000/namespace/awesome-project. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_project_url : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_REF_PATH]. + + The ref path of the merge request. For example, refs/merge-requests/1/head. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_ref_path : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SOURCE_BRANCH_NAME]. + + The source branch name of the merge request. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_source_branch_name : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED]. + + ["true"] when the source branch of the merge request is protected. + + Context: merge requests. Available since GitLab [16.4]. + Available in [all] runners. *) +val ci_merge_request_source_branch_protected : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SOURCE_BRANCH_SHA]. + + The HEAD SHA of the source branch of the merge request. The variable is + empty in merge request pipelines. The SHA is present only in merged results + pipelines. + + Context: merge requests. Available since GitLab [11.9]. + Available in [all] runners. *) +val ci_merge_request_source_branch_sha : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SOURCE_PROJECT_ID]. + + The ID of the source project of the merge request. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_source_project_id : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SOURCE_PROJECT_PATH]. + + The path of the source project of the merge request. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_source_project_path : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SOURCE_PROJECT_URL]. + + The URL of the source project of the merge request. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_source_project_url : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_SQUASH_ON_MERGE]. + + ["true"] when the squash on merge option is set. + + Context: merge requests. Available since GitLab [16.4]. + Available in [all] runners. *) +val ci_merge_request_squash_on_merge : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_TARGET_BRANCH_NAME]. + + The target branch name of the merge request. + + Context: merge requests. Available since GitLab [11.6]. + Available in [all] runners. *) +val ci_merge_request_target_branch_name : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED]. + + ["true"] when the target branch of the merge request is protected. + + Context: merge requests. Available since GitLab [15.2]. + Available in [all] runners. *) +val ci_merge_request_target_branch_protected : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_TARGET_BRANCH_SHA]. + + The HEAD SHA of the target branch of the merge request. The variable is + empty in merge request pipelines. The SHA is present only in merged results + pipelines. + + Context: merge requests. Available since GitLab [11.9]. + Available in [all] runners. *) +val ci_merge_request_target_branch_sha : Var.t + +(** Corresponds to [CI_MERGE_REQUEST_TITLE]. + + The title of the merge request. + + Context: merge requests. Available since GitLab [11.9]. + Available in [all] runners. *) +val ci_merge_request_title : Var.t diff --git a/ci/lib_gitlab_ci/to_yaml.ml b/ci/lib_gitlab_ci/to_yaml.ml new file mode 100644 index 0000000000000000000000000000000000000000..9340e99d813b9008fc0223372ca0fe36b2b7101b --- /dev/null +++ b/ci/lib_gitlab_ci/to_yaml.ml @@ -0,0 +1,265 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +open Yaml +open Yaml.Util +open Types + +(* Helpers *) + +let opt name f = function Some v -> [(name, f v)] | None -> [] + +let obj_flatten fields = `O (List.concat fields) + +let key name f value : (string * value) list = [(name, f value)] + +let array f values = `A (List.map f values) + +(* Equivalent to [array f values] unless [values] is a singleton [x], + in which case it is encoded as [f x]. + + This is useful for more succint encoding of fields like [cache:] + that can either take an array of values, or a single value. *) +let array1 f values = + match values with [value] -> f value | _ -> array f values + +let strings ss : value = array string ss + +let int i = float (float_of_int i) + +(* Translation elements *) + +let enc_if expr = string @@ If.encode expr + +let enc_variables (vars : variables) : value = + `O (List.map (fun (name, value) -> (name, `String value)) vars) + +let enc_when : when_ -> value = function + | Always -> `String "always" + | Never -> `String "never" + | On_success -> `String "on_success" + | Manual -> `String "manual" + | Delayed _ -> `String "delayed" + +let enc_when_workflow : when_workflow -> value = function + | Always -> `String "always" + | Never -> `String "never" + +let enc_when_artifact : when_artifact -> value = function + | Always -> `String "always" + | On_failure -> `String "on_failure" + | On_success -> `String "on_success" + +let enc_when_job : when_job -> value = function + | Always -> `String "always" + | On_success -> `String "on_success" + | Manual -> `String "manual" + +let enc_workflow_rule : workflow_rule -> value = + fun {changes; if_; variables; when_} -> + obj_flatten + [ + opt "changes" strings changes; + opt "if" enc_if if_; + opt "variables" enc_variables variables; + key "when" enc_when_workflow when_; + ] + +let enc_allow_failure_rule (allow_failure : allow_failure_rule) : value = + match allow_failure with Yes -> `Bool true | No -> `Bool false + +let enc_time_interval interval = + `String + (match interval with + | Seconds 1 -> "1 second" + | Seconds x -> string_of_int x ^ " seconds" + | Minutes 1 -> "1 minute" + | Minutes x -> string_of_int x ^ " minutes" + | Hours 1 -> "1 hour" + | Hours x -> string_of_int x ^ " hours" + | Days 1 -> "1 day" + | Days x -> string_of_int x ^ " days" + | Weeks 1 -> "1 week" + | Weeks x -> string_of_int x ^ " weeks" + | Months 1 -> "1 month" + | Months x -> string_of_int x ^ " months" + | Years 1 -> "1 year" + | Years x -> string_of_int x ^ " years") + +let enc_job_rule : job_rule -> value = + fun {changes; if_; variables; when_; allow_failure} -> + let start_in = + match when_ with Delayed start_in -> Some start_in | _ -> None + in + obj_flatten + [ + opt "changes" strings changes; + opt "if" enc_if if_; + opt "variables" enc_variables variables; + key "when" enc_when when_; + opt "allow_failure" enc_allow_failure_rule allow_failure; + opt "start_in" enc_time_interval start_in; + ] + +let enc_include_rule : include_rule -> value = + fun {changes; if_; when_} -> + obj_flatten + [ + opt "changes" strings changes; + opt "if" enc_if if_; + key "when" enc_when_workflow when_; + ] + +let enc_workflow_rules : workflow_rule list -> value = array enc_workflow_rule + +let enc_job_rules : job_rule list -> value = array enc_job_rule + +let enc_include_rules : include_rule list -> value = array enc_include_rule + +let enc_workflow : workflow -> value = function + | {name; rules} -> + obj_flatten [opt "name" string name; key "rules" enc_workflow_rules rules] + +let enc_stages stages : value = strings stages + +let enc_image (Image image) = string image + +let enc_default ({image; interruptible} : default) : value = + obj_flatten + [opt "image" enc_image image; opt "interruptible" bool interruptible] + +let enc_coverage : coverage_report -> value = + fun {coverage_format; path} -> + obj_flatten + [ + key + "coverage_format" + (function Cobertura -> `String "cobertura") + coverage_format; + key "path" string path; + ] + +let enc_report : reports -> value = + fun {dotenv; junit; coverage_report} -> + obj_flatten + [ + opt "dotenv" string dotenv; + opt "junit" string junit; + opt "coverage_report" enc_coverage coverage_report; + ] + +let enc_artifacts : artifacts -> value = + fun {expire_in; paths; reports; when_; expose_as; name} -> + obj_flatten + [ + opt "name" string name; + opt "expire_in" enc_time_interval expire_in; + key "paths" strings paths; + opt "reports" enc_report reports; + opt "when" enc_when_artifact when_; + opt "expose_as" string expose_as; + ] + +let enc_cache : cache -> value = + fun {key = k; paths} -> + obj_flatten [key "key" string k; key "paths" strings paths] + +let enc_service ({name} : service) : value = `String name + +let enc_services (ss : service list) : value = array enc_service ss + +let enc_allow_failure_job (allow_failure : allow_failure_job) : value = + match allow_failure with + | Yes -> `Bool true + | No -> `Bool false + | With_exit_codes codes -> `O [("exit_codes", array1 int codes)] + +let enc_needs (needs : need list) : value = + (* Use terse encoding unless optional is set to true for at least one need *) + let enc_need = + if List.for_all (fun {job = _; optional} -> optional = false) needs then + fun {job; optional = _} -> `String job + else fun {job; optional} -> + `O + ([("job", `String job)] + @ if optional then [("optional", `Bool true)] else []) + in + array enc_need needs + +let enc_job : job -> value = + fun { + name = _; + after_script; + allow_failure; + artifacts; + before_script; + cache; + image; + interruptible; + needs; + dependencies; + rules; + script; + services; + stage; + variables; + timeout; + tags; + when_; + coverage; + retry; + parallel; + } -> + obj_flatten + [ + opt "image" enc_image image; + opt "stage" string stage; + opt "tags" (array string) tags; + opt "rules" enc_job_rules rules; + opt "needs" enc_needs needs; + opt "dependencies" strings dependencies; + opt "allow_failure" enc_allow_failure_job allow_failure; + opt "timeout" enc_time_interval timeout; + opt "cache" (array1 enc_cache) cache; + opt "interruptible" bool interruptible; + key "script" strings script; + opt "after_script" strings after_script; + opt "before_script" strings before_script; + opt "services" enc_services services; + opt "variables" enc_variables variables; + opt "artifacts" enc_artifacts artifacts; + opt "when" enc_when_job when_; + opt "coverage" string coverage; + opt "retry" int retry; + opt "parallel" int parallel; + ] + +let enc_includes : include_ list -> value = + fun includes -> + let enc_includes ({local; rules} : include_) = + match rules with + | [] -> `String local + | _ :: _ -> + `O [("local", `String local); ("rules", enc_include_rules rules)] + in + match includes with + | [] -> failwith "empty includes" + | [{local; rules = []}] -> `String local + | inc -> array enc_includes inc + +let config_element : config_element -> string * value = function + | Workflow wf -> ("workflow", enc_workflow wf) + | Stages ss -> ("stages", enc_stages ss) + | Variables vars -> ("variables", enc_variables vars) + | Default def -> ("default", enc_default def) + | Job j -> (j.name, enc_job j) + | Include i -> ("include", enc_includes i) + +let to_yaml (config : config) : value = `O (List.map config_element config) + +let to_file ?header ~filename config = + Base.write_yaml ?header filename (to_yaml config) diff --git a/ci/lib_gitlab_ci/to_yaml.mli b/ci/lib_gitlab_ci/to_yaml.mli new file mode 100644 index 0000000000000000000000000000000000000000..9a1013210cfd19c1380b16f3122b682899d0d2e1 --- /dev/null +++ b/ci/lib_gitlab_ci/to_yaml.mli @@ -0,0 +1,14 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** The YAML representation of a GitLab CI configuration. *) +val to_yaml : Types.config -> Yaml.value + +(** Writes the YAML representation of a GitLab CI configuration to a file. + + If set, [?header] is prepended to the file. *) +val to_file : ?header:string -> filename:string -> Types.config -> unit diff --git a/ci/lib_gitlab_ci/types.ml b/ci/lib_gitlab_ci/types.ml new file mode 100644 index 0000000000000000000000000000000000000000..dbc6fd1db684c7c73529cd8aa8ec833407e62691 --- /dev/null +++ b/ci/lib_gitlab_ci/types.ml @@ -0,0 +1,148 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** The AST of GitLab CI configurations. + + For reference, see GitLab's {{:https://docs.gitlab.com/ee/ci/yaml/} CI/CD YAML syntax reference}. *) + +type variables = (string * string) list + +type time_interval = + | Seconds of int + | Minutes of int + | Hours of int + | Days of int + | Weeks of int + | Months of int + | Years of int + +(** Represents values of the [when:] field in job rules. *) +type when_ = Always | Never | On_success | Manual | Delayed of time_interval + +(** Represents values of the [when:] field of jobs. *) +type when_job = Always | On_success | Manual + +(** Represents values of the [when:] field in [workflow:] and [include:] rules. *) +type when_workflow = Always | Never + +(** Represents values of the [job:allow_failure:] field of rules. *) +type allow_failure_job = Yes | No | With_exit_codes of int list + +(** Represents values of the [rules:allow_failure:] field of rules. + + GitLab does not enable allowing a set of exit codes in rules, + as is possible in a job's [allow_failure] field. *) +type allow_failure_rule = Yes | No + +(** Represents a job rule. *) +type job_rule = { + changes : string list option; + if_ : If.t option; + variables : variables option; + when_ : when_; + allow_failure : allow_failure_rule option; +} + +(** Represents a workflow rule. *) +type workflow_rule = { + changes : string list option; + if_ : If.t option; + variables : variables option; + when_ : when_workflow; +} + +(** Represents an include rule. *) +type include_rule = { + changes : string list option; + if_ : If.t option; + when_ : when_workflow; +} + +type coverage_format = Cobertura + +type coverage_report = {coverage_format : coverage_format; path : string} + +type reports = { + dotenv : string option; + junit : string option; + coverage_report : coverage_report option; +} + +type image = Image of string + +type when_artifact = Always | On_success | On_failure + +type artifacts = { + expire_in : time_interval option; + paths : string list; + reports : reports option; + when_ : when_artifact option; + expose_as : string option; + name : string option; +} + +type default = {image : image option; interruptible : bool option} + +type cache = {key : string; paths : string list} + +type service = {name : string} + +type need = {job : string; optional : bool} + +type job = { + name : string; + (** Note that [name] does not translate to a field in a job, but + instead to the key in the top-level that identifies the job. *) + after_script : string list option; + allow_failure : allow_failure_job option; + artifacts : artifacts option; + before_script : string list option; + cache : cache list option; + image : image option; + interruptible : bool option; + needs : need list option; + dependencies : string list option; + rules : job_rule list option; + script : string list; + services : service list option; + stage : string option; + variables : variables option; + timeout : time_interval option; + tags : string list option; + when_ : when_job option; + coverage : string option; + (** Note: the job field [coverage] is not to be confused with + {!coverage_report}. + {{:https://docs.gitlab.com/ee/ci/yaml/#coverage}This + coverage field} is used to specify a regular expression that + can be used to capture coverage information from the job's + trace. On the other hand, {!coverage_report} is used to + expose the captured coverage information as a report in a + job's artifacts + ({{:https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report}ref}). *) + retry : int option; + parallel : int option; +} + +type workflow = {rules : workflow_rule list; name : string option} + +type include_ = {local : string; rules : include_rule list} + +type config_element = + | Workflow of workflow (** Corresponds to a [workflow:] key. *) + | Stages of string list (** Corresponds to a [stages:] key. *) + | Variables of variables (** Corresponds to a [variables:] key. *) + | Default of default (** Corresponds to a [default:] key. *) + | Job of job (** Corresponds to a job, identified by it's key. *) + | Include of include_ list (** Corresponds to a [include:] key *) + +(** A GitLab CI/CD configuration. + + Note that a configuration can consists of a sequence of + [config_element]s. The same element can occur multiple times, and + their order has semantic significance (for instance, with [include:]). *) +type config = config_element list diff --git a/ci/lib_gitlab_ci/util.ml b/ci/lib_gitlab_ci/util.ml new file mode 100644 index 0000000000000000000000000000000000000000..62a3c9e62949840686a732cf9b1a20c6931444e3 --- /dev/null +++ b/ci/lib_gitlab_ci/util.ml @@ -0,0 +1,76 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +open Types + +let default ?image ?interruptible () : default = {image; interruptible} + +let job_rule ?changes ?if_ ?variables ?(when_ : when_ = On_success) + ?allow_failure () : job_rule = + (* Swap the + {{:https://docs.gitlab.com/ee/ci/yaml/#allow_failure}default} of + [allow_failure] for manual rules. This makes the default case + non-blocking, and blocking rules have to be demanded + explicitly. *) + let allow_failure = + match (when_, allow_failure) with + | Manual, None -> Some Yes + | _ -> allow_failure + in + {changes; if_; variables; when_; allow_failure} + +let workflow_rule ?changes ?if_ ?variables ?(when_ : when_workflow = Always) () + : workflow_rule = + {changes; if_; variables; when_} + +let include_rule ?changes ?if_ ?(when_ : when_workflow = Always) () : + include_rule = + {changes; if_; when_} + +let job ?after_script ?allow_failure ?artifacts ?before_script ?cache ?image + ?interruptible ?needs ?dependencies ?rules ?services ?stage ?variables + ?timeout ?tags ?when_ ?coverage ?retry ?parallel ~name ~script () = + { + name; + after_script; + allow_failure; + artifacts; + before_script; + cache; + image; + interruptible; + needs; + dependencies; + rules; + script; + services; + stage; + variables; + timeout; + tags; + when_; + coverage; + retry; + parallel; + } + +let artifacts ?expire_in ?reports ?when_ ?expose_as ?name paths = + (match (reports, paths) with + | Some {dotenv = None; junit = None; coverage_report = None}, [] -> + failwith + "Attempted to register an artifact with no reports or paths -- this \ + doesn't make any sense" + | _ -> ()) ; + {expire_in; paths; reports; when_; expose_as; name} + +let reports ?dotenv ?junit ?coverage_report () = + (match (dotenv, junit, coverage_report) with + | None, None, None -> + failwith + "Attempted to register a empty [reports] -- this doesn't make any sense" + | _ -> ()) ; + {dotenv; junit; coverage_report} diff --git a/ci/lib_gitlab_ci/util.mli b/ci/lib_gitlab_ci/util.mli new file mode 100644 index 0000000000000000000000000000000000000000..4727575dd4b186c5337e8d735a289f95dfce2128 --- /dev/null +++ b/ci/lib_gitlab_ci/util.mli @@ -0,0 +1,111 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2023 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** Smart constructors for values of {!Types} *) + +open Types + +(** Constructs a [default:] configuration element. *) +val default : ?image:image -> ?interruptible:bool -> unit -> default + +(** Constructs a job rule. + + [when_] defaults to [On_success]. + + If [when_] is set to [Manual] then the default [allow_failure] + will be overwritten to allow failure, to avoid blocking jobs. + This typically makes sense unless you truly want a job to block + the execution of all later jobs (i.e. for a trigger-type job). If + you want to make such a job, set [~allow_failure] explicitly: + [job_rule ~when_:Manual ~allow_failure:false ()]. *) +val job_rule : + ?changes:string list -> + ?if_:If.t -> + ?variables:variables -> + ?when_:when_ -> + ?allow_failure:allow_failure_rule -> + unit -> + job_rule + +(** Constructs a workflow rule. + + [when_] defaults to [Always]. *) +val workflow_rule : + ?changes:string list -> + ?if_:If.t -> + ?variables:variables -> + ?when_:when_workflow -> + unit -> + workflow_rule + +(** Constructs an include rule. + + Include rules do not permit [variables] and there is consequently + no such parameter. + + [when_] defaults to [Always]. *) +val include_rule : + ?changes:string list -> + ?if_:If.t -> + ?when_:when_workflow -> + unit -> + include_rule + +(** Constructs a job. *) +val job : + ?after_script:string list -> + ?allow_failure:allow_failure_job -> + ?artifacts:artifacts -> + ?before_script:string list -> + ?cache:cache list -> + ?image:image -> + ?interruptible:bool -> + ?needs:need list -> + ?dependencies:string list -> + ?rules:job_rule list -> + ?services:service list -> + ?stage:string -> + ?variables:variables -> + ?timeout:time_interval -> + ?tags:string list -> + ?when_:when_job -> + ?coverage:string -> + ?retry:int -> + ?parallel:int -> + name:string -> + script:string list -> + unit -> + job + +(** [artifacts paths] Construct an [artifacts:] clause storing [paths]. + + - [expire_in:] is omitted if [expire_in] is [None]. + - [reports:] is omitted if [reports] is [None]. + - [when:] is omitted if [when_] is [None]. + - [expose_as:] is omitted if [expose_as] is [None]. + + At least one of [paths] or [reports] must be non-empty. *) +val artifacts : + ?expire_in:time_interval -> + ?reports:reports -> + ?when_:when_artifact -> + ?expose_as:string -> + ?name:string -> + string list -> + artifacts + +(** Construct an [reports:] clause for [artifacts:]. + + - [dotenv:] is omitted if [dotenv] is [None]. + - [junit:] is omitted if [junit] is [None]. + - [coverage_report:] is omitted if [coverage_report] is [None]. *) +val reports : + ?dotenv:string -> + ?junit:string -> + ?coverage_report:coverage_report -> + unit -> + reports diff --git a/ci/lib_gitlab_ci/var.ml b/ci/lib_gitlab_ci/var.ml new file mode 100644 index 0000000000000000000000000000000000000000..1a696ab470f67e7b6a0f8ae161823fcb8b59c7b3 --- /dev/null +++ b/ci/lib_gitlab_ci/var.ml @@ -0,0 +1,26 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +open Base + +type t = string + +let encode = Fun.id + +let make variable_name = + (* See + {{:https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/pipeline/expression/lexeme/variable.rb#L9}string.rb}} + for valid variable names. *) + if + String.exists + (function + | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' -> false | _ -> true) + variable_name + then + raise + (Invalid_argument (sf "[Var.t] invalid variable name '%s'" variable_name)) ; + "$" ^ variable_name diff --git a/ci/lib_gitlab_ci/var.mli b/ci/lib_gitlab_ci/var.mli new file mode 100644 index 0000000000000000000000000000000000000000..b63c1383b7c6604a4d0ad1a7d93f4dd6debda6b3 --- /dev/null +++ b/ci/lib_gitlab_ci/var.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +(** GitLab CI Configuration variables *) + +(** Variables in GitLab CI configurations. + + Variables appear in: + - GitLab [if:] expressions + - Job scripts + and elsewhere (see + {{:https://docs.gitlab.com/ee/ci/variables/where_variables_can_be_used.html} + here} for more information) *) +type t + +(** [make variable_name] creates a variable called [variable_name]. + + Raises [Invalid_argument] if the [name] is not composed + exclusively of characters from the set [a-zA-Z0-9_]. *) +val make : string -> t + +(** The string representation of a variable. + + [encode @@ make "foo"] is ["$foo"]. *) +val encode : t -> string diff --git a/dune-project b/dune-project index d73a6eebe79ed2ffe18dec626871e75ff7bdd8b8..799d9d540cce5f3d4d17964907efd5770dd4d00b 100644 --- a/dune-project +++ b/dune-project @@ -4,6 +4,7 @@ (using ctypes 0.3) (using menhir 2.1) (package (name bls12-381)) +(package (name gitlab_ci)) (package (name internal-devtools)) (package (name internal-devtools_proto-context-du)) (package (name kaitai)) diff --git a/manifest/main.ml b/manifest/main.ml index b4852c883fdd242e46260e20aaa6be6cbb790e43..6b3ca36215992dcf7752a79d052dbe7999c11d63 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -8764,6 +8764,16 @@ let _docs_doc_gen_errors = Protocol.(client_exn alpha) |> open_; ] +let _ci_lib_gitlab_ci_main = + public_lib + "gitlab_ci" + ~synopsis:"OCaml library for generating GitLab CI YAML configuration files" + ~path:"ci/lib_gitlab_ci" + ~bisect_ppx:No + ~deps:[yaml] + ~inline_tests:ppx_expect + ~release_status:Unreleased + (* Add entries to this function to declare that some dune and .opam files are not generated by the manifest on purpose. diff --git a/opam/gitlab_ci.opam b/opam/gitlab_ci.opam new file mode 100644 index 0000000000000000000000000000000000000000..632028338d5afe22593a430e263e0ee02d3debdb --- /dev/null +++ b/opam/gitlab_ci.opam @@ -0,0 +1,21 @@ +# This file was automatically generated, do not edit. +# Edit file manifest/main.ml instead. +opam-version: "2.0" +maintainer: "contact@tezos.com" +authors: ["Tezos devteam"] +homepage: "https://www.tezos.com/" +bug-reports: "https://gitlab.com/tezos/tezos/issues" +dev-repo: "git+https://gitlab.com/tezos/tezos.git" +license: "MIT" +depends: [ + "dune" { >= "3.11.1" } + "ocaml" { >= "4.14" } + "ppx_expect" + "yaml" { >= "3.1.0" } +] +build: [ + ["rm" "-r" "vendors" "contrib"] + ["dune" "build" "-p" name "-j" jobs] + ["dune" "runtest" "-p" name "-j" jobs] {with-test} +] +synopsis: "OCaml library for generating GitLab CI YAML configuration files"