sourceconditiontarget

Description

The githubrelease resource reads the releases published on a GitHub repository.

source

Returns the latest release, sorted by release date.

condition

Checks that tag corresponds to a published release.

target

Not supported - a target fails with target not supported for the plugin GitHub Release. Updatecli does not publish releases; to create a tag, use gittag.

Note
An scm attached to a condition is ignored, with the warning condition not supported for plugin GitHub Release used with scm.

Releases and tags are not the same list

When a repository has no releases, Updatecli falls back to its tags, sorted by tag creation date.

The two lists are mutually exclusive: a repository that publishes releases is read through the release list only, so a tag without a matching release is invisible. This is the usual explanation for a version that exists on GitHub but that a source will not return.

Parameters

NameTypeDescriptionRequired
appobject“app” specifies the GitHub App credentials used to authenticate with GitHub API. It is not compatible with the “token” and “username” fields. It is recommended to use the GitHub App authentication method for better security and granular permissions. For more information, please refer to the following documentation:
    clientidstringClientID represents the GitHub App client ID
    expirationtimestring

Expiration represents the token expiration time in seconds The token is used during the entire execution of updatecli and should be valid for the entire duration of the run The minimum value is 600 seconds (10 minutes)

Default: 3600 (1 hour)

    installationidstringInstallationID represents the GitHub App installation ID It is the same ID that you can find in the GitHub endpoint: https://github.com/settings/installation/
    privatekeystringPrivateKey represents a PEM encoded private key It is recommended to use PrivateKeyPath instead of PrivateKey to avoid putting sensitive information in the configuration file If both PrivateKey and PrivateKeyPath are set, PrivateKey takes precedence
    privatekeypathstringPrivateKeyPath represents the path to a PEM encoded private key If both PrivateKey and PrivateKeyPath are set, PrivateKey takes precedence It is recommended to use an environment variable to set the PrivateKeyPath value e.g. PrivateKeyPath: {{ requiredEnv “GITHUB_APP_PRIVATE_KEY_PATH” }} to avoid putting sensitive information in the configuration file
keystring

“key” defines the GitHub release information we are looking for. It accepts one of the following inputs:

  • “name”: returns the “latest” tag name
  • “hash”: returns the commit associated with the latest tag name
  • “title”: returns the latest release title

accepted values:

  • taghash
  • tagname
  • title
  • hash (deprecated)
  • name (deprecated)

default: ’tagname'

compatible:

  • source
  • condition
ownerstring

owner defines repository owner to interact with.

required: true

compatible:

  • source
  • condition
repositorystring

repository defines the repository name to interact with.

required: true

compatible:

  • source
  • condition
tagstring

tag allows to check for a specific release tag, release tag hash, or release title depending on a the parameter key.

compatible:

  • condition

default: source input

tokenstring

token defines the GitHub personal access token used to authenticate with.

more information on https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens

required: true

compatible:

  • source
  • condition
typefilterobject

typeFilter specifies the GitHub Release type to retrieve before applying the versionfilter rule

default:

  • draft: false
  • prerelease: false
  • release: true
  • latest: false

compatible:

  • source
    • condition
    draftboolean“Draft” enable/disable GitHub draft release
    latestboolean“Latest” if set to true will only filter the release flag as latest.
    prereleaseboolean“PreRelease” enable/disable GitHub PreRelease
    releaseboolean“Release” enable/disable GitHub release
urlstring

URL defines the default github url in case of GitHub enterprise.

default: https://github.com

compatible:

  • source
  • condition
usernamestring

username defines the username used to authenticate with GitHub API.

compatible:

  • source
  • condition
versionfilterobject

versionFilter provides parameters to specify version pattern and its type like regex, semver, or just latest.

default: latest

compatible:

  • source
    kindstringspecifies the version kind such as semver, regex, or latest
    patternstringspecifies the version pattern according the version kind for semver, it is a semver constraint for regex, it is a regex pattern for time, it is a date format
    regexstringspecifies the regex pattern, used for regex/semver and regex/time. Output of the first capture group will be used.
    replaceallobjectreplaceAll applies a regex replacement to version strings before filtering. This is useful for transforming versions (e.g., curl-8_15_0 to curl-8.15.0) before regex extraction.
    strictbooleanstrict enforce strict versioning rule. Only used for semantic versioning at this time

owner and repository are mandatory. tag is condition-only.

key

key chooses what the source returns:

ValueReturns

tagname

The tag name. The default.

taghash

The commit hash the tag points at.

title

The release title.

name and hash are deprecated aliases for tagname and taghash; they still work and log a warning. Anything else is a validation error listing the accepted values.

typefilter

typefilter selects which kinds of release count. Its default is the important part:

spec:
  typefilter:
    draft: false
    prerelease: false
    release: true
    latest: false

When draft, prerelease and release are all left unset, release is turned on - so out of the box only stable releases are considered, and pre-releases are ignored. Set prerelease: true to include them.

latest: true narrows the result to the single release GitHub itself flags as "Latest", which is not necessarily the most recent one by date.

Authentication

Updatecli supports multiple authentication methods for interacting with GitHub. You can authenticate using either a Personal Access Token (PAT) or a GitHub App. Below are the supported methods; the order in which Updatecli picks one is described under Precedence and Fallback at the end of this section.


1. GitHub App Authentication via Environment Variables

Set the following environment variables to enable GitHub App authentication:

  • UPDATECLI_GITHUB_APP_CLIENT_ID: Your GitHub App’s Client ID

  • UPDATECLI_GITHUB_APP_PRIVATE_KEY: The private key for your GitHub App (PEM format, as a string)

  • UPDATECLI_GITHUB_APP_PRIVATE_KEY_PATH: The path to your GitHub App’s private key file (PEM format)

  • UPDATECLI_GITHUB_APP_INSTALLATION_ID: The installation ID for your GitHub App

  • UPDATECLI_GITHUB_APP_EXPIRATION_TIME: Optional token lifetime in seconds. Defaults to 3600 (one hour), the minimum accepted value is 600

You can use either UPDATECLI_GITHUB_APP_PRIVATE_KEY or UPDATECLI_GITHUB_APP_PRIVATE_KEY_PATH to provide the private key.

Example using the private key content:

export UPDATECLI_GITHUB_APP_CLIENT_ID="123456"
export UPDATECLI_GITHUB_APP_PRIVATE_KEY="$(cat /path/to/private-key.pem)"
export UPDATECLI_GITHUB_APP_INSTALLATION_ID="789012"

Example using the private key path:

export UPDATECLI_GITHUB_APP_CLIENT_ID="123456"
export UPDATECLI_GITHUB_APP_PRIVATE_KEY_PATH="/path/to/private-key.pem"
export UPDATECLI_GITHUB_APP_INSTALLATION_ID="789012"
Note

When these variables are set and UPDATECLI_GITHUB_TOKEN is not, Updatecli uses GitHub App authentication for all GitHub operations, ignoring any credential set in the manifest.

If the four variables do not form a valid configuration (a missing private key, an installation ID that is not an integer, an expiration below 600 seconds), the whole set is silently ignored and Updatecli moves on to the next method. Run with --debug to see which credential was selected.


2. Personal Access Token via Environment Variable

Set the following environment variable to use a Personal Access Token:

  • UPDATECLI_GITHUB_TOKEN: Your GitHub Personal Access Token

  • UPDATECLI_GITHUB_USERNAME: Your GitHub username. Optional; Updatecli uses oauth2 when it is unset.

Example:

export UPDATECLI_GITHUB_TOKEN="ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXX"

This is the credential Updatecli looks at first. When it is set, every other method below is ignored, including the ones declared in the manifest.


3. Personal Access Token via Manifest

You can specify your Personal Access Token directly in your Updatecli manifest under the spec.token field:

scms:
  default:
    kind: github
    spec:
      owner: myorg
      repository: myrepo
      token: "{{ requiredEnv `GITHUB_TOKEN` }}"
Warning

For security reasons, it is recommended to use environment variables or secret management tools (like SOPS) instead of hardcoding tokens in your manifest.


4. GitHub App Authentication via Manifest

You can configure GitHub App authentication directly in your manifest using the spec.app field:

scms:
  default:
    kind: github
    spec:
      owner: myorg
      repository: myrepo
      app:
        clientID: "123456"
        privateKey: "{{ requiredEnv `GITHUB_APP_PRIVATE_KEY` }}"
        installationID: "789012"

Or, if you prefer to reference a private key file:

scms:
  default:
    kind: github
    spec:
      owner: myorg
      repository: myrepo
      app:
        clientID: "123456"
        privateKeyPath: "/path/to/private-key.pem"
        installationID: "789012"

Precedence and Fallback

Updatecli uses the first credential it finds, in the following order:

  1. UPDATECLI_GITHUB_TOKEN environment variable

  2. UPDATECLI_GITHUB_APP_* environment variables

  3. spec.token in the manifest

  4. spec.app in the manifest

  5. GITHUB_TOKEN environment variable

The environment always wins over the manifest: a spec.token is dead weight as soon as UPDATECLI_GITHUB_TOKEN is exported, which is a common surprise when a manifest behaves differently on a workstation and in CI.

GITHUB_TOKEN is a last-resort fallback, meant for GitHub Actions where the runner exports it automatically. It is only consulted once every other method has come up empty.

Warning

spec.token and spec.app cannot be combined in the same manifest. Doing so fails at load time with you cannot use both token and app authentication methods.

If no credential is found at all, Updatecli builds an unauthenticated GraphQL client instead of stopping immediately. Read-only resources may still work against public repositories, but every scm operation fails as soon as it needs the credential:

failed to get access token: no access token found

Further Reading


Tip: For best security and maintainability, prefer using a GitHub App or environment variables for authentication, and avoid hardcoding secrets in your manifests.

app configures GitHub App authentication and is not compatible with token and username. It is the better option where it is available: scoped permissions and short-lived credentials.

Important
Storing credentials in an unencrypted file is a bad practice. Read the token from an environment variable with '{{ requiredEnv "GITHUB_TOKEN" }}'.

Version Filter

versionFilter allows to specify the kind of version retrieved from a resource and its version pattern. Default value is "latest" as we want to retrieve the newest version from a resource.

A version filter accepts the following keys:

NameDefaultDescription

kind

latest

One of latest, lex, regex, semver, regex/semver, time, regex/time, pep440. An unsupported value stops the run with an error.

pattern

depends on kind

The constraint applied to the versions, interpreted according to kind. Defaults to . for regex, for semver and pep440, and 2006-01-02 for time and regex/time.

regex

-

Used by regex/semver and regex/time only, to extract the version from a longer string. The first capture group is the value being filtered.

replaceall

-

An optional find-and-replace applied to each version before the filter, with the sub-keys pattern (a regular expression) and replacement (which may reference capture groups with $1, $2, …).

strict

false

Used by semver and regex/semver only. When true, only strictly formatted MAJOR.MINOR.PATCH versions are considered, so a lenient version such as 1.2 is dropped instead of being read as 1.2.0.

Note
Versions that cannot be parsed for the selected kind are silently skipped, not treated as errors. When nothing is left after filtering, the resource fails with "no version found".

latest

If kind is set to latest then there is no need to specify a pattern, as Updatecli returns the last version provided by the resource, in the order the resource returned them.

Important
latest does not compare versions, it trusts the ordering of the resource. For a Docker registry, that is the most recently pushed tag, which is not necessarily the highest version number. Use semver when you need the highest version.
Example
sources:
  kubectl:
    kind: githubRelease
    spec:
      owner: "kubernetes"
      repository: "kubectl"
      token: "{{ requiredEnv .github.token }}"
      username: "john"
      versionFilter:
        kind: latest
    transformers:
      - trimPrefix: "kubernetes-"

Return the latest Github release and remove "kubernetes-" from it.

Lex

If the kind is set to lex then Updatecli returns the latest version sorted lexicographically.

Sorting versions lexicographically means arranging them based on their lexicographic order, which is essentially alphabetical order as used in dictionaries, but applied to version strings.

For example, in lexicographic order:

"1.10" comes before "1.2", because it compares character by character:
    Compare "1" vs. "1" → equal.
    Compare "." vs "." → equal.
    Compare "1" vs. "2" → "1" is smaller, so "1.10" < "1.2".

This ordering does not account for numerical values of version components. For meaningful version comparisons, semantic versioning is typically preferred, where "1.2" < "1.10" because "2" is numerically smaller than "10".

Example
sources:
  ubuntu-focal:
    name: Get latest ubuntu focal docker image tag using regex/time versionfilter
    kind: dockerimage
    spec:
      image: ubuntu
      versionfilter:
        kind: lex

regex

If versionFilter.kind is set to regex then we can use versionFilter.pattern to specify a regular expression to return the newest version returned from a resource matching the regex If no versionFilter.pattern is provided then it uses '.*' which return the newest version

Note
Like latest, regex walks the versions in the order the resource returned them and stops on the first match, starting from the end. It filters, it does not sort. To compare version numbers, use regex/semver.

versionFilter.replaceall can optionally be used to transform version strings before the regex is applied. It accepts a pattern (regex) and a replacement string, similar to a find-and-replace operation.

sources:
  kubectl:
    kind: githubRelease
    spec:
      owner: "kubernetes"
      repository: "kubectl"
      token: "{{ requiredEnv .github.token }}"
      username: "john"
      versionFilter:
        kind: regex
        pattern: "kubernetes-1.(\\d*).(\\d*)$"
    transformers:
      - trimPrefix: "kubernetes-"

⇒ Return the newest kubectl version matching pattern "kubernetes-1.(\\d*).(\\d*)$" and remove "kubernetes-" from it

Example with replaceall

Some projects use version tags that are not directly compatible with the regex pattern. For example, curl uses tags like curl-8_11_1 where underscores separate version components. The replaceall option can be used to normalize these tags before applying the regex.

sources:
  curl:
    kind: githubRelease
    spec:
      owner: "curl"
      repository: "curl"
      versionFilter:
        kind: regex
        pattern: 'curl-\d+\.\d+\.\d+'
        replaceall:
          pattern: "_"
          replacement: "."

⇒ The replaceall converts curl-8_11_1 to curl-8.11.1, and the newest tag matching pattern is returned as curl-8.11.1

Important
With kind: regex, the returned value is the whole transformed version, not a capture group - the regex key is ignored, only pattern is read. Use kind: regex/semver when you need to extract 8.11.1 out of curl-8.11.1, and add a trimprefix transformer otherwise.

semver

If versionFilter.kind is set to semver then we can use versionFilter.pattern to specify version pattern as explained here. In the process we also sort. If no versionFilter.pattern is provided then it falls back to '*' which returns the newest version. Versions that do not respect semantic versioning are ignored.

Setting versionFilter.strict to true additionally rejects versions that are only loosely semantic, such as 1.2 or v1, instead of completing them with zeros.

Remark

In the process we drop any characters not respecting semantic version like in this version "v1.0.0", we drop the "v" but we can add it back using transformers.

Autodiscovery patterns

On top of the standard constraints, semver accepts the following keywords, which are resolved against the version currently in use. They are what the autodiscovery crawlers use to restrict the scope of an update.

PatternMeaning

patch

Only patch updates, keeping the same major and minor.

minor

Minor and patch updates, keeping the same major.

minoronly

Minor updates only, excluding patch updates within the current minor.

major

Any update from the current major upwards.

majoronly

Major updates only.

prerelease

Pre-releases of the current version.

Example
  jenkins-wiki-exporter:
    kind: githubRelease
    spec:
      owner: "jenkins-infra"
      repository: "jenkins-wiki-exporter"
      token: "{{ requiredEnv .github.token }}"
      username: "john"
      versionFilter:
        kind: semver
        pattern: "~1.10"

⇒ Return the version "v1.10.3"

regex/semver

If versionFilter.kind is set to regex/semver then we can use versionFilter.regex to specify a regular expression to extract version numbers. The regular expression should return the semantic version in the first capturing group. We can then use versionFilter.pattern to specify version pattern as explained here. In the process we also sort. If no versionFilter.pattern is provided then it falls back to '*' which returns the newest version. Extracted values that do not respect semantic versioning are ignored.

versionFilter.replaceall can optionally be used to transform version strings before the regex is applied. It accepts a pattern (regex) and a replacement string, similar to a find-and-replace operation. See the regex section for an example.

Important
The regular expression must define at least one capture group; a version without one is skipped. pattern filters the extracted value, regex extracts it (the two are not interchangeable).
Example
sources:
  default:
    name: Get latest version
    kind: githubrelease
    spec:
      owner: yarnpkg
      repository: berry
      token: '{{ requiredEnv "GITHUB_TOKEN" }}'
      versionfilter:
        kind: regex/semver
        regex: "@yarnpkg/cli/(\\d*\\.\\d*\\.\\d*)"

⇒ Return the version "4.5.3"

regex/time

If versionFilter.kind is set to regex/time then we can use versionFilter.regex to specify a regular expression to extract dates. The regular expression should return the date in the first capturing group. We can then use versionFilter.pattern to specify date pattern as explained here. In the process we also sort. If no versionFilter.pattern is provided then it falls back to '2006-01-02' which returns the newest version using date format YYYY-MM-DD. Extracted values that do not match the date pattern are ignored.

To define your own format/pattern, write down what the reference time would look like formatted your way; The model is to demonstrate what the reference time looks like so that the Format and Parse methods can apply the same transformation to a general time value.

Here is a summary of the components of a layout string. Each element shows by example the formatting of an element of the reference time. Only these values are recognized. Text in the layout string that is not recognized as part of the reference time is echoed verbatim during Format and expected to appear verbatim in the input to Parse.

Year: "2006" "06"
Month: "Jan" "January" "01" "1"
Day of the week: "Mon" "Monday"
Day of the month: "2" "_2" "02"
Day of the year: "__2" "002"
Hour: "15" "3" "03" (PM or AM)
Minute: "4" "04"
Second: "5" "05"
AM/PM mark: "PM"

You can get inspiration from the following examples

Pattern

Example

2006-01-02

2021-01-02 (YYYY-MM-DD)

20060102

20210102 (YYYYMMDD)

20060201

20260201 (YYYYDDMM)

Example
sources:
  ubuntu-focal:
    name: Get latest ubuntu focal docker image tag using regex/time versionfilter
    kind: dockerimage
    spec:
      image: ubuntu
      versionfilter:
        kind: 'regex/time'
        regex: '^focal-(\d*)$'
        pattern: "20060102"

time

If versionFilter.kind is set to time then we can use versionFilter.pattern to specify date pattern as explained here. In the process we also sort. If no versionFilter.pattern is provided then it fallback to '2006-01-02' which return the newest version using date format YYYY-MM-DD. Please note date time not matching the pattern will be ignored.

To define your own format/pattern, write down what the reference time would look like formatted your way; The model is to demonstrate what the reference time looks like so that the Format and Parse methods can apply the same transformation to a general time value.

Here is a summary of the components of a layout string. Each element shows by example the formatting of an element of the reference time. Only these values are recognized. Text in the layout string that is not recognized as part of the reference time is echoed verbatim during Format and expected to appear verbatim in the input to Parse.

Year: "2006" "06"
Month: "Jan" "January" "01" "1"
Day of the week: "Mon" "Monday"
Day of the month: "2" "_2" "02"
Day of the year: "__2" "002"
Hour: "15" "3" "03" (PM or AM)
Minute: "4" "04"
Second: "5" "05"
AM/PM mark: "PM"

You can get inspiration from the following examples

Pattern

Example

2006-01-02

2021-01-02 (YYYY-MM-DD)

20060102

20210102 (YYYYMMDD)

20060201

20260201 (YYYYDDMM)

Example
sources:
  ubuntu:
    name: Get latest ubuntu docker image tag using time versionfilter
    kind: dockerimage
    spec:
      image: ubuntu
      versionfilter:
        kind: 'time'
        pattern: "06.01"

pep440

If versionFilter.kind is set to pep440 then versions are parsed and sorted according to the Python PEP 440 specification, and versionFilter.pattern is a PEP 440 specifier such as >=1.0,<2.0. Versions that are not valid PEP 440 versions are ignored.

This is the right choice for Python packages, whose versions are not semantic versions: PEP 440 understands epochs (1!2.0), post-releases (1.0.post1), development releases (1.0.dev1), and pre-release spellings such as 1.0rc1 or 1.0a1, which semver rejects or misorders.

If no versionFilter.pattern is provided then it falls back to *.

Important
With *, or with no pattern at all, Updatecli returns the newest stable version and only falls back to a pre-release when no stable version exists. An explicit specifier does not apply that preference: it returns the newest version satisfying it, pre-release or not.
Example
sources:
  ansible:
    name: Get the latest stable Ansible release
    kind: pypi
    spec:
      name: ansible
      versionfilter:
        kind: pep440
# source.yaml
sources:
  lastRelease:
    kind: githubRelease
    spec:
      owner: "jenkins-infra"
      repository: "jenkins-wiki-exporter"
      token: "{{ requiredEnv "ENV_VARIABLE" }}"
      username: "john"
      versionFilter:
        kind: regexp
        pattern: "v1.10\.(.*)"

⇒ Returns v1.10.3

Example

# updatecli.yaml
name: Github Release Example

# Scms defines Git repository configuration to interact with.
scms:
  default:
    kind: github
    spec:
      user: "updatecli"
      email: "updatecli@olblak.com"
      owner: "olblak"
      repository: "charts"
      token: '{{ requiredEnv "GITHUB_TOKEN" }}'
      username: "olblak"
      branch: "master"

# Sources are responsible for retrieving information from thirds location like GitHub releases.
sources:
  # Retrieve the "latest" Helm version using the Helm GitHub Release.
  helm:
    name: Get latest Helm release version
    kind: githubrelease
    spec:
      owner: "helm"
      repository: "helm"
      token: '{{ requiredEnv .github.token }}'
      username: olblak
      versionfilter:
        kind: latest

# Conditions are simple checks that need to pass before updating a target.
conditions:
  # The yaml plugin doesn't support advanced yamlpath syntax so when we need
  # to fetch information from an array, we want to be sure that the position is 
  # still relevant to the target
  keyExist:
    name: Update GitHub Action workflow
    kind: yaml
    scmid: default
    disablesourceinput: true
    spec:
      file: .github/workflows/helm.yaml
      key: .$jobs.release.steps[0].name
      value: Install Helm

# Targets define the state of files based on source information.
targets:
  # Ensure the Dockerfile arg HELM_VERSION is set to the latest Helm version retrieved by the source.
  dockerfile:
    name: Update Dockerfile ARG HELM_VERSION
    kind: dockerfile
    scmid: default
    sourceid: helm
    spec:
      file: docker/Dockerfile
      instruction:
        keyword: ARG
        matcher: HELM_VERSION

  # Ensure the GitHub workflow file is correctly set to the latest helm version retrieved from the source.
  ghWorkflow:
    name: Update GitHub Action workflow
    kind: yaml
    scmid: default
    sourceid: helm
    spec:
      file: .github/workflows/helm.yaml
      key: .$jobs.release.steps[0].with.version

actions:
  # If one of the two targets is modified, then we want to open a
  # pullrequest with the auto merge flag set to true and the label "helm"
  default:
    kind: github/pullrequest
    scmid: default
    title: 'Bump Helm version to {{ source "helm" }}'
    spec:
      merge:
        strategy: auto
      labels:
        - "helm"