# Configuration<no value>
// <!-- Required for asciidoctor -->
:toc:
// Set toclevels to be at least your hugo [markup.tableOfContents.endLevel] config key
:toclevels: 4

Updatecli requires a configuration file, or "manifest", which describes the update pipeline.
A manifest describes the "what", the "when", and the "where" of the update pipeline.

**What**

The "what" is the "source" and defines what piece of information we're looking for, such as the latest application release version, a docker image tag, etc.

**When**

The "when" is a "condition", if the condition is satisfied then the target is updated.

**Where**

The "where" is the "target" and defines where we want to update a piece of information like a value from a Dockerfile or YAML file.


== Manifest

=== Root keys

A manifest accepts the following root keys. All of them are optional except `name`.

[cols="1,1,3",options=header]
|===
| Key | Type | Description

| `name`
| string
| A short sentence describing the pipeline. It is reused as a default value elsewhere, such as the pull request title, so it should not embed dynamic information like a source output.

| `pipelineid`
| string
| Identifies a full pipeline run, and groups manifests into the same Git branch and pull request. See <<_pipeline_id,Pipeline ID>>.

| `id`
| string
| Declares a manifest identifier other manifests can depend on. See link:/docs/core/order/[manifest order].

| `dependson`
| list of string
| Lists the manifest `id` values that must run before this manifest. See link:/docs/core/order/[manifest order].

| `labels`
| map of string
| Arbitrary key/value pairs used to filter pipelines at runtime and in reports. See link:/docs/core/label/[labels].

| `version`
| string
| The minimum Updatecli version required by the manifest. Updatecli skips the manifest, with an error, when its own version is lower.

| `options`
| object
| Settings changing how Updatecli behaves for this manifest, as opposed to describing the pipeline itself. See <<_options,Options>>.

| `sources`
| map
| See link:/docs/core/source/[source].

| `conditions`
| map
| See link:/docs/core/condition/[condition].

| `targets`
| map
| See link:/docs/core/target/[target].

| `scms`
| map
| Git repository configurations shared by the resources of the manifest. See link:/docs/core/scm/[scm].

| `actions`
| map
| What to do once a target changed, typically opening a pull request. See link:/docs/core/action/[action].

| `autodiscovery`
| object
| Generates pipelines automatically instead of writing them. See link:/docs/core/autodiscovery/[autodiscovery].
|===

NOTE: `title` and `pullrequests` are deprecated in favor of `name` and `actions`. Updatecli still accepts them but logs a warning, and `pullrequests` and `actions` are mutually exclusive.

[#_pipeline_id]
=== Pipeline ID

By default, Updatecli treats each manifest file as an independent update pipeline.
For reproducibility, it automatically generates a deterministic pipeline ID based on the manifest’s content.
This ensures that the same manifest always gets the same pipeline ID across multiple runs.

Updatecli uses this ID in several places, such as the name of the temporary branch it creates when preparing pull requests.

If multiple manifest files share the same pipeline ID (either because they have identical content or because you explicitly set the same pipelineid), they will share the same temporary branch.

++++
<details><summary>updatecli.d/docker.yaml</summary>

<pre>
name: Update Golang Version in Dockerfile
pipelineid: go/version
...
</pre>
</details>
++++

++++
<details><summary>updatecli.d/gomod.yaml</summary>

<pre>
name: Update Golang Version in Go Mod
pipelineid: go/version
...
</pre>
</details>
++++

[IMPORTANT]
====
* When `pipelineid` is not set, Updatecli generates one:
** from a hash of the manifest `name`, when a `name` is defined.
** from a checksum of the whole manifest file, when no `name` is defined. In that case the ID changes every time the file content changes, and so does the temporary branch name.
+
Defining a `name` (or better, an explicit `pipelineid`) is therefore the recommended way to keep a stable branch across runs.
* Since the pipelineid is used in the name of the temporary Git branch, avoid using / in the ID.
In Git, / is treated as a directory separator in branch names, which can make branch management confusing.
====

=== Manifest Order

When running multiple manifests, Updatecli can order them explicitly with the root keys `id` and `dependson`.

Use `id` to declare a manifest identifier, and `dependson` to list which manifest IDs must run first.
This affects manifest execution order only and does not replace `pipelineid`.

To learn more, see **link:/docs/core/order/[manifest order]**.

[#_options]
=== Options

The `options` root key groups the settings that change how Updatecli behaves for a manifest, as opposed to the keys describing what the pipeline is made of.

[cols="1,1,3",options=header]
|===
| Key | Default | Description

| `relativepaths`
| `workingdirectory`
| What the relative paths of the manifest resolve against. See <<_relative_paths,Relative paths>>.
|===

[#_relative_paths]
==== Relative paths

By default, a relative path written in a manifest resolves against the directory Updatecli was started from, not against the manifest that declares it.
A manifest stored in `updatecli.d/nodejs.yaml` and asking for `file: package.json` therefore reads the `package.json` of whichever directory you happened to run the command in.

Setting `relativepaths` to `manifest` makes those paths resolve against the directory holding the manifest instead, which is what allows a manifest, or a whole directory of them, to be moved, vendored into another repository, or distributed as a link:/docs/core/shareandreuse/[policy] without rewriting every path.

[cols="1,3",options=header]
|===
| Value | Behaviour

| `workingdirectory`
| Relative paths resolve against the directory Updatecli was started from. This is the default, and the historical behaviour.

| `manifest`
| Relative paths resolve against the directory holding the manifest that declares them.
|===

++++
<details><summary>updatecli.yaml</summary>
<pre>
{{<include "assets/code_example/docs/core/configuration/relativepaths.yaml">}}
</pre>
</details>
++++

The setting applies to the manifest that declares it, so a directory of manifests can be migrated one file at a time.
It can also be set for a whole run, with the `--relative-paths` flag or the `UPDATECLI_RELATIVE_PATHS` environment variable, which is the practical way to try it on an existing repository:

[source,shell]
----
updatecli diff --relative-paths manifest --config updatecli.d
----

A manifest declaring `options.relativepaths` wins over the flag and the environment variable.

[IMPORTANT]
====
`relativepaths` mostly affects resources that are **not** attached to an link:/docs/core/scm/[scm].

A source, condition, or target with an `scmid` resolves its file paths against the working directory of that scm, which is the clone Updatecli made for it. That is unchanged, and is what makes a target committed to the right repository.

The exception is the `path` of the link:/docs/plugins/resource/gittag/[gittag], link:/docs/plugins/resource/gitbranch/[gitbranch], and link:/docs/plugins/resource/gitcommit/[gitcommit] resources. With `relativepaths: manifest`, a relative `path` resolves from the manifest directory even when the resource has an `scmid`.
====

Within a manifest that sets `relativepaths: manifest`, the manifest directory becomes the base for:

* the file paths of every resource without an `scmid`, such as `spec.file` and `spec.files`
* the working directory of the link:/docs/plugins/resource/shell/[shell] resource, `spec.workdir`
* a relative `directory` in an `scms` entry, and the repository the `local` scm auto-detects
* the directory the link:/docs/core/autodiscovery/[autodiscovery] crawlers scan

Absolute paths are never rewritten, and `http://` or `https://` locations are always fetched over the network rather than read from disk.

NOTE: The values, secrets, and manifest files passed on the command line with `--values`, `--secrets`, and `--config` are resolved against the directory Updatecli was started from, whatever `relativepaths` says. They are arguments to the command, not content of a manifest.

[TIP]
====
The default stays `workingdirectory` on purpose. The most common layout is a `updatecli.d/` directory whose manifests reference paths from the root of the repository, and those manifests only work because paths resolve against the working directory. Changing the default would break them, so opting in per manifest is the supported path.
====

=== File

Each Updatecli pipeline is defined in its own manifest file.
The manifest is split into different stages, "sources", "conditions", "targets",
where every stage relies on a plugin to adapt the behavior.

Every manifest is parsed as a Go template first, then as YAML.
The following file extensions are accepted:

[cols="1,3",options=header]
|===
| Extension | Remark
| `.yaml`, `.yml` | The most common choice.
| `.tpl`, `.tmpl` | Same content as a YAML manifest, the extension only signals the templating intent.
| `.json` | JSON is a subset of YAML, so JSON manifests are accepted too.
| `.cue` | https://cuelang.org[CUE] manifests, **experimental**: requires the `--experimental` flag.
|===

Any other extension is silently ignored, which allows keeping unrelated files next to your manifests in the same directory.

==== Passing manifests to Updatecli

Manifests are given to the updatecli command using the flag `--config` (`-c`).
It accepts either a single file or a directory.
If a directory is specified, then Updatecli runs recursively on all supported files in that directory.

When `--config` is not specified, Updatecli looks, in the current directory, for:

. a file named `updatecli.yaml` (plus `updatecli.cue` in experimental mode)
. a directory named `updatecli.d`

Both are used if both exist. If neither is found, Updatecli falls back to the default
link:/docs/core/autodiscovery/[autodiscovery] crawlers.

Templating values are provided with the following flags:

[cols="1,3",options=header]
|===
| Flag | Description
| `--values`, `-v` | A YAML or JSON file containing key/values, repeatable.
| `--values-inline`, `-i` | An inline YAML or JSON string containing key/values, repeatable.
| `--secrets` | A https://github.com/getsops/sops[SOPS] encrypted YAML or JSON file, repeatable.
|===

When the same key is defined more than once, the last one wins: values files are merged in order,
then secrets files override them, then inline values override everything.
The merge is recursive, so two values files can contribute different keys to the same nested object.

==== Multiple pipelines in a single file

A manifest file may contain several YAML documents separated by `---`.
Updatecli loads each document as an independent pipeline.

[source,yaml]
----
name: Update Golang version in the Dockerfile
sources:
  # ...
---
name: Update Golang version in go.mod
sources:
  # ...
----

IMPORTANT: Manifest files starting with an underscore `_` are considered as partial files and are not executed. More information on the partial section below.

=== Partial

Partials are named, reusable fragments of an Updatecli manifest, typically used to define repeatable logic for:

* Scms (e.g., Git repository details)
* Sources (e.g., version checks)
* Conditions
* Targets

These fragments are automatically available to pipelines within the same directory, helping keep your main manifests DRY (Don't Repeat Yourself) and maintainable.

A partial file must:

* have a filename that starts with an underscore (`_`)
* use the `.yaml` or `.yml` extension
* live in the *same directory* as the manifest that uses it. Partials from other directories are ignored, even when Updatecli walks a directory tree.

Updatecli never loads a partial as a standalone manifest.

[IMPORTANT]
====
* Partial files are prepended to the main manifest before templating, and the result is parsed as a single YAML document. A partial can therefore only define root keys that the main manifest does not already define (a duplicated root key is a YAML error).
* If a `---` YAML document separator is present, the partial feature is effectively disabled, as the resulting content would be treated as multiple separate YAML documents.
====

++++
<details><summary>updatecli.yaml</summary>

<pre>
autodiscovery:
  groupby: {{ .groupby }}
#{{ if or (.scm.enabled) }}
  scmid: default
  actionid: default
# {{ end }}

  crawlers:
    golang/gomod:

</pre>
</details>

++++

++++
<details><summary>_scm.yaml</summary>

<pre>
# {{ if and (.scm.enabled) ( eq .scm.kind "gitea")) }}
actions:
    default:
        title: 'deps: bump HUGO to {{ source "hugo" }}'
        kind: "gitea/pullrequest"
        scmid: "default"

scms:
    default:
        kind: "gitea"
        spec:
            user: '{{ .scm.user }}'
            # {{ if .scm.email }}
            email: '{{ .scm.email }}'
            # {{ end }}
            owner: '{{ .scm.owner }}'
            repository: '{{ .scm.repository }}'
            token: '{{ .scm.token }}'
            username: '{{ .scm.username }}'
            branch: '{{ .scm.branch }}'
            # {{ if .scm.url }}
            url: '{{ .scm.url }}'
            # {{ end }}
# {{ end }}
</pre>
</details>

++++


=== Content

Using go templates allows us to specify generic values in a different YAML file, using `--values`.
We then reference those values from each go template.

More information on Go templates is https://golang.org/pkg/text/template/[here].

==== Template functions

On top of the standard Go template functions, a manifest can use:

* all functions from the https://masterminds.github.io/sprig/[Sprig template library]
* the Helm-flavored `toYaml`, `fromYaml`, and `fromYamlArray` functions
* the Updatecli specific functions described below

[cols="1,3",options=header]
|===
| Function | Description

| `requiredEnv`
| Injects an environment variable, and fails the run when the variable is empty or undefined, for example `{{ requiredEnv "GITHUB_TOKEN" }}`.

| `source`
| Injects the output of another source of the same pipeline, for example `{{ source "latestVersion" }}`.

| `pipeline`
| Injects any value from the running pipeline configuration, using a dot separated path, for example `{{ pipeline "Sources.latestVersion.Output" }}` or `{{ pipeline "Name" }}`.
|===

[IMPORTANT]
====
`source` and `pipeline` are *not* evaluated when the manifest is loaded (at that point the values do not exist yet).
They are re-evaluated during the pipeline run, each time a resource completes, and only then replaced by their value.

As a side effect, `{{ source "id" }}` also declares an execution dependency: a resource referencing it
automatically waits for the source `id` to run first. See link:/docs/core/order/[manifest order] for details.

Sprig's `env` function, on the contrary, is evaluated at load time like the rest of the template.
====

An example values file can contain:

++++
<details><summary>values.yaml</summary>
<pre>
{{<include "assets/code_example/docs/core/configuration/values.yaml">}}
</pre>
</details>
++++

That can used in a pipeline manifest as:

++++
<details><summary>updatecli.yaml</summary>
<pre>
{{<include "assets/code_example/docs/core/configuration/updatecli.yaml">}}
</pre>

</details>
++++

== Go Further

* To know more about Condition syntax **link:/docs/core/condition/[condition]**
* To know more about Source syntax **link:/docs/core/source/[source]**
* To know more about Target syntax **link:/docs/core/target/[target]**
* To know more about manifest and resource ordering **link:/docs/core/order/[manifest order]**
* To know more about pipeline filtering **link:/docs/core/label/[labels]**
* To know more about **link:/plugins/[Plugins]**
** More specifically about the **link:/plugins/source/[source]**
** More specifically about the **link:/plugins/condition/[condition]**
** More specifically about the **link:/plugins/target/[target]**
** More specifically about the **link:/plugins/scm/[SCM]**
