Description

The github scm plugin clones a GitHub repository locally so that other resources can read from it, and pushes changes back to it. It is referenced by a resource through its scmid, as described on the "SCM" page.

Its behavior depends on the stage referencing it:

source and condition

The repository is cloned and the resource works on the files from the branch defined by branch. Nothing is pushed.

target

Updatecli creates a working branch based on branch, commits the changes to it, and pushes that branch to the remote. The branch value itself is never modified.

Important
This plugin does not open pull requests. Pushing a working branch and opening a pull request are two distinct steps: the pull request is created by an actions block of kind github/pullrequest, documented on the "GitHub Pull Request" page. Without such an action, the working branch is pushed and nothing else happens.

If you only need to read from GitHub without cloning a repository (for instance the latest release of a project), use a resource such as githubrelease instead of an scm.

Requirements

A GitHub credential is required, including for public repositories. The scm authenticates every git operation, so without a usable credential the pipeline fails at clone time with:

failed to get access token: no access token found

See Authentication below for the accepted credentials and the order in which they are tried.

The credential needs read access to the repository for a source or a condition, and write access to the repository contents for a target. A github/pullrequest action additionally needs permission to open pull requests.

Parameters

NameTypeDescriptionRequired
appobject

“app” defines the GitHub App credentials used to authenticate with the GitHub API.

remark:

  • “app” and “token” are mutually exclusive, and “username” is ignored when “app” is set.
  • a GitHub App gives better security and finer permissions than a personal token.
  • see https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation
    clientidstring“clientid” defines the GitHub App client ID.
    expirationtimestring

“expirationtime” defines the lifetime of the GitHub App token, in seconds.

default: 3600

remark:

  • the token is used during the whole Updatecli run, so it must stay valid until the run ends.
  • the minimum value is 600.
    installationidstring

“installationid” defines the GitHub App installation ID.

remark:

  • the value must be an integer.
  • it is the ID shown in the URL https://github.com/settings/installation/
    privatekeystring

“privatekey” defines the PEM encoded private key of the GitHub App.

remark:

  • “privatekey” or “privatekeypath” is required.
  • when both are set, “privatekey” takes precedence.
  • prefer “privatekeypath”, to keep sensitive information out of the manifest.
    privatekeypathstring

“privatekeypath” defines the path to a file holding the PEM encoded private key of the GitHub App.

remark:

  • “privatekey” or “privatekeypath” is required.
  • when both are set, “privatekey” takes precedence.
  • setting the value from an environment variable keeps sensitive information out of the manifest.

example:

  • privatekeypath: ‘{{ requiredEnv “GITHUB_APP_PRIVATE_KEY_PATH” }}’
branchstring

“branch” defines the git branch to work on.

remark:

  • there is no default, so set it explicitly. Only the GitHub scm that Updatecli generates from the local git repository uses “main” when it is unset.
  • when the GitHub scm is used by a source or a condition, files are read from this branch.
  • when the GitHub scm is used by a target, Updatecli pushes changes to a working branch based on this branch, named “updatecli__” by default.
  • set “workingbranch” to false to push changes directly to this branch.

example:

  • branch: main
commitmessageobject

“commitmessage” defines the settings used to generate commit messages.

remark:

  • the settings apply to every target using this scm.
    bodystring

“body” defines the conventional commit body.

default: empty, which means the body is generated by Updatecli.

remark:

  • see https://www.conventionalcommits.org/en/
    deprecatedtitlestring

“title” is ignored.

deprecated:

  • the commit title is always generated from the target name or description.
    footersstring

“footers” defines the conventional commit footers.

default: empty

remark:

  • see https://www.conventionalcommits.org/en/
    hidecreditboolean

“hidecredit” defines whether the Updatecli credit line is left out of the commit message body.

default: false

remark:

  • if you disable the credit line, please consider sponsoring the Updatecli project, https://github.com/updatecli/updatecli
    scopestring

“scope” defines the conventional commit scope.

default: empty

remark:

  • see https://www.conventionalcommits.org/en/
    squashboolean

“squash” defines whether the commits are squashed into a single commit.

default: false

remark:

  • squashing loses the other commit messages, so setting a meaningful “body” is recommended.
  • when “body” is empty, the squashed commit message is generated from the most recent squashed commit. The title is always generated from the target name or description.
    titlestringTitle is the parsed commit message title (not configurable via YAML). The title is automatically generated from the target name or description.
    typestring

“type” defines the conventional commit type, such as “chore”, “fix” or “feat”.

default: chore

remark:

  • see https://www.conventionalcommits.org/en/
commitusingapiboolean

“commitusingapi” defines whether Updatecli creates commits with the GitHub GraphQL API instead of git.

default: false

remark:

  • GitHub signs the commits created this way from a GitHub Actions workflow using the GITHUB_TOKEN. See https://github.com/updatecli/updatecli/issues/1914
depthinteger

“depth” defines the depth used when cloning the git repository.

default: empty, which means a full clone.

remark:

  • a value greater than 0 creates a shallow clone, so Updatecli cannot see the full git history. Pushing changes may then fail, in which case setting “force” to true may be needed.
  • a negative value is rejected.

example:

  • depth: 1
directorystring

“directory” defines the local path where the git repository is cloned.

default: a directory under the Updatecli temporary directory, such as “/tmp/updatecli/github//” on Linux.

remark:

  • keep the default value unless you have a good reason to change it, as Updatecli may delete the directory after a pipeline run.
emailstring

“email” defines the email address used to author commits.

default: updatecli-bot@updatecli.io

forceboolean

“force” defines whether Updatecli runs git push --force when pushing changes.

default: true

remark:

  • when true, Updatecli also recreates the working branches that diverged from their base branch.
  • when “workingbranch” is false and “force” is not set, the GitHub scm returns an error, to avoid force pushing to “branch” by mistake. Set “force” explicitly to confirm the behavior.
gpgobject“gpg” defines the GPG key and passphrase used to sign commits.
    passphrasestring“passphrase” defines the passphrase that unlocks “signingkey”.
    signingkeystring

“signingkey” defines the armored GPG private key used to sign commits.

default: empty, which means commits are not signed.

remark:

  • the value is the key content, not a key ID.
  • a private key is sensitive, so avoid writing it in the manifest.
ownerstring“owner” defines the owner of the repository.
repositorystring“repository” defines the name of the repository.
singlebranchboolean

“singlebranch” defines whether Updatecli clones and fetches only the configured branch, instead of every branch, tag and other reference of the remote.

default: false

remark:

  • enabling it can make operations much faster on repositories with many branches, tags or other references, because Updatecli skips the fetch that mirrors every remote reference.
  • in some edge cases, Updatecli may then miss a working branch that was already pushed, and open a duplicate pull request.
submodulesboolean

“submodules” defines whether Updatecli clones the git submodules of the repository.

default: true

tokenstring

“token” defines the token used to authenticate with the GitHub API.

remark:

  • “token” and “app” are mutually exclusive.
  • a token is sensitive, so avoid writing it in the manifest. Read it from an environment variable with {{ requiredEnv "GITHUB_TOKEN" }}, or from a SOPS file with {{ .github.token }}. See https://github.com/getsops/sops
  • the environment variable UPDATECLI_GITHUB_TOKEN, or the UPDATECLI_GITHUB_APP_* environment variables, take precedence over this value.
  • when no credential is set, Updatecli falls back to the environment variable GITHUB_TOKEN.
urlstring

“url” defines the GitHub URL, to use a GitHub Enterprise instance.

default: github.com

remark:

  • the scheme “https://” is added when missing.

example:

  • url: github.example.com
userstring

“user” defines the name used to author commits.

default: updatecli-bot

usernamestring

“username” defines the username used with the token to authenticate with the GitHub API.

remark:

  • the token is usually enough on its own. A username may be needed for private repositories.
workingbranchboolean

“workingbranch” defines whether Updatecli pushes changes to a temporary working branch based on “branch”, instead of pushing to “branch” directly.

default: true

workingbranchprefixstring

“workingbranchprefix” defines the prefix of the working branch name.

default: updatecli

remark:

  • the working branch name joins the prefix, the target branch and the pipeline ID, separated by “workingbranchseparator”.
  • when set to an empty string, the name starts with the separator, for example “main”.
workingbranchseparatorstring

“workingbranchseparator” defines the separator between the parts of the working branch name.

default: _

owner and repository are the only mandatory parameters. Everything else has a default or is optional.

Note
The table above is generated from the Updatecli JSON schema, which is refreshed by a bot after each Updatecli release. A parameter added very recently (currently singleBranch, which restricts clone and fetch to the configured branch) may be usable by the binary before it appears here.

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.

Branch and working branch

branch is the branch resources read from, and the branch a target’s changes are ultimately meant for. Updatecli never commits directly to it unless you explicitly opt out of the working branch.

For a target, the working branch is derived from three components joined by a separator:

<workingBranchPrefix><workingBranchSeparator><branch><workingBranchSeparator><pipelineID>

With the defaults (workingBranchPrefix: updatecli, workingBranchSeparator: _), a pipeline updating main produces a branch such as updatecli_main_6f3c…​. The pipelineID component is a hash derived from the pipeline, so the same pipeline always reuses the same working branch instead of piling up new ones. Characters GitHub does not accept in a ref are stripped or replaced, and the result is truncated to 255 characters.

Setting workingBranchPrefix to an empty string drops the prefix, giving <branch>_<pipelineID>.

Disabling the working branch

Setting workingBranch: false makes Updatecli commit and push directly to branch. Because force defaults to true (meaning git push --force), this combination is refused unless you also set force explicitly:

Better safe than sorry.

Updatecli may be pushing unwanted changes to the branch "main".

Set force: false to push without forcing, or force: true to acknowledge the force push. Note that when force is true, Updatecli also recreates working branches that have diverged from their base branch.

Cleaning up working branches

updatecli apply --clean-git-branches deletes, at the end of the run, every working branch that ended up identical to its base branch - the branches left behind by pipelines that turned out to have nothing to change. Branches carrying actual commits are kept. The flag has no effect on a dry run (updatecli diff) or when pushing is disabled.

Commit message

Updatecli generates conventional commits, to give commit messages a meaning that is readable by both humans and machines. The commitMessage parameters (type, scope, body, footers, hideCredit, squash) shape the generated message.

The commit title is always generated from the target’s name, or from its description when name is unset. The title is capped at 72 characters, minus the room taken by type and scope; anything longer is truncated with an ellipsis and the remainder is moved into the commit body. With the default type chore, this produces:

Author: olblak <updatecli-bot@updatecli.io>
Date:   Tue May 4 15:41:44 2021 +0200

    chore: Update key "dependencies[0].version" from file "charts/jenkins/r...

    ... equirements.yaml"

    Made with ❤️️  by updatecli

Setting body replaces the generated body entirely, including the truncated remainder shown above. hideCredit: true removes the "Made with ❤️️ by updatecli" line.

Warning

commitMessage.title is deprecated and ignored. Rename the target instead - the commit title now always comes from the target name. Updatecli logs a warning when the field is present.

squash: true rewrites the commits added on the working branch into a single commit. Since all intermediate commit information is lost, set body to something meaningful when squashing.

Note
The commitMessage settings apply to every target linked to the same scm.

Commit signing

Two independent mechanisms are available.

gpg

signingkey takes an armored private GPG key and passphrase its password. Updatecli signs the commit locally with that key.

commitUsingApi

When set to true, the commit is created through the GitHub GraphQL API rather than by the local git client. GitHub then signs the commit itself with its own key - this is how a workflow running under GITHUB_TOKEN produces a verified commit without managing a GPG key. Updatecli creates the working branch through the API when it does not exist yet, then pulls the resulting commit back into the local clone.

Note

squash is not supported together with commitUsingApi. The option is ignored and a warning is logged.

Clone behavior

By default the repository is cloned under your system temporary directory, at <tmp>/updatecli/github/<owner>/<repository> - for example /tmp/updatecli/github/updatecli/updatecli on Linux. Overriding directory is rarely useful, as Updatecli may clean that directory up after a run.

Three parameters control how much is fetched, all of them trade-offs on large repositories:

submodules

Defaults to true. Set it to false to skip submodule checkout.

depth

Number of commits to fetch. Unset means a full clone. A shallow clone gives Updatecli an incomplete history, which can break pushes; setting force: true is often necessary alongside it.

singleBranch

Defaults to false, meaning every branch, tag, and ref is fetched. Set it to true to fetch only branch, which is significantly faster on repositories with many refs. In return, Updatecli may fail to notice an already published working branch in some edge cases, and open a duplicate pull request.

On a repository with a large number of refs, singleBranch is the option that pays off: it skips the fetch that otherwise mirrors every branch, tag, and pull request ref from the remote. It only applies when branch is set. See Large repositories for a full manifest.

GitHub Enterprise

Point url at your instance, for example github.example.com. The scheme is optional and defaults to https://. Updatecli then talks to the GraphQL API at <url>/api/graphql and clones from <url>/<owner>/<repository>.git. Left unset, url defaults to github.com.

API rate limits

Updatecli checks the remaining GitHub API quota before its GraphQL calls. When the limit is exceeded, it pauses until the quota resets and retries, up to three times, before failing the pipeline. Run with --debug to see the quota reported at each call.

Example

Default

# updatecli.yaml
name: Example of a GitHub SCM configuration

scms:
  default:
    kind: github
    spec:
      # owner and repository are the only mandatory parameters
      owner: updatecli
      repository: updatecli
      # branch resources read from, and the base branch of the working branch
      # created for targets
      branch: main
      # credentials, better provided by the UPDATECLI_GITHUB_TOKEN environment
      # variable than by the manifest
      token: '{{ requiredEnv "GITHUB_TOKEN" }}'
      username: '{{ requiredEnv "GITHUB_ACTOR" }}'
      # identity used for the git commits, defaults to updatecli-bot
      user: updatecli-bot
      email: updatecli-bot@updatecli.io

targets:
  # the target name is used as the commit title
  updateChartVersion:
    name: 'deps: bump chart dependency version'
    kind: yaml
    scmid: default
    spec:
      file: charts/jenkins/Chart.yaml
      key: $.version

CommitMessage

# updatecli.yaml
name: Example with a GitHub commit message

scms:
  default:
    kind: github
    spec:
      owner: updatecli
      repository: updatecli
      branch: main
      token: '{{ requiredEnv "GITHUB_TOKEN" }}'
      commitmessage:
        # produces "deps(charts): <target name>"
        type: deps
        scope: charts
        footers: 'Signed-off-by: updatecli-bot <updatecli-bot@updatecli.io>'
        # remove the "Made with ❤️ by updatecli" line from the commit body
        hidecredit: true
        # squash every commit of the working branch into one, using the body below
        squash: true
        body: |
          This commit was generated by Updatecli.

targets:
  # the commit title comes from this name, "commitmessage.title" is deprecated
  updateChartVersion:
    name: 'bump chart dependency version'
    kind: yaml
    scmid: default
    spec:
      file: charts/jenkins/Chart.yaml
      key: $.version

GitHub App

# updatecli.yaml
name: Example of a GitHub SCM authenticated with a GitHub App

scms:
  default:
    kind: github
    spec:
      owner: updatecli
      repository: updatecli
      branch: main
      # "app" and "token" are mutually exclusive
      app:
        clientid: '{{ requiredEnv "GITHUB_APP_CLIENT_ID" }}'
        installationid: '{{ requiredEnv "GITHUB_APP_INSTALLATION_ID" }}'
        # privatekey and privatekeypath are both accepted,
        # privatekey takes precedence when both are set
        privatekeypath: '{{ requiredEnv "GITHUB_APP_PRIVATE_KEY_PATH" }}'
        # token lifetime in seconds, 3600 by default, 600 minimum
        expirationtime: "3600"

targets:
  updateChartVersion:
    name: 'deps: bump chart dependency version'
    kind: yaml
    scmid: default
    spec:
      file: charts/jenkins/Chart.yaml
      key: $.version

Large repositories

# updatecli.yaml
name: Example of a GitHub SCM configuration optimized for large repositories

scms:
  default:
    kind: github
    spec:
      user: "git user to push from changes"
      email: "git user email to push from change"
      directory: "directory where to clone the git repository"
      owner: "github owner"
      repository: "github repository"
      token: "github token with enough permission on repository"
      username: "github username used for push git changes. Needed in private repositories"
      branch: "git branch where to push changes"
      singleBranch: true

targets:
  id:
    kind: yaml
    scmid: default
    spec:
      file: "Yaml file path from the root repository"
      key: "yaml key to update"