Description

githubsearch is not an scm you clone from - it is a generator. Before anything else runs, Updatecli sends your query to the GitHub repository search API, lists the branches of every repository it finds, keeps the branches matching branch, and turns each surviving repository/branch pair into a regular github scm.

Your manifest is then duplicated once per pair, each copy pinned to one repository and one branch. Ten matches mean ten pipelines, ten working branches, and (if the manifest declares a github/pullrequest action) ten pull requests. Everything the github scm documentation says about cloning, working branches, commits, and signing applies unchanged to each copy.

This makes githubsearch the way to roll one change across an organisation without listing its repositories by hand.

Its behavior depends on the stage referencing it:

source and condition

Each discovered repository is cloned and the resource works on the files from the matched branch. Nothing is pushed.

target

Updatecli creates a working branch in each discovered repository, commits the changes there, and pushes it.

Important
Like the github scm, this plugin does not open pull requests. That is the job of an actions block of kind github/pullrequest, documented on the "GitHub Pull Request" page.

Requirements

A GitHub credential is required, including for public repositories - see Authentication. On top of the permissions each discovered repository needs, the credential must be allowed to use the repository search API, since discovery happens before any repository is cloned.

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 a regular expression matching the git branches to work on.

default: ^main$

remark:

  • one GitHub scm is generated for each matching branch of each discovered repository.
  • when a generated scm is used by a source or a condition, files are read from the matching branch.
  • when a generated scm is used by a target, Updatecli pushes changes to a working branch based on the matching branch, named “updatecli__” by default.
  • set “workingbranch” to false to push changes directly to the matching branch.

example:

  • branch: ^main$
  • branch: ^release/.*$
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.
  • the value is passed as is to every generated scm., so every repository then uses the same directory.
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, each generated 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.
limitinteger

“limit” defines the maximum number of GitHub scm generated from the search results.

default: 10

remark:

  • 0 means no limit.
  • one scm is generated for each matching branch of each repository, so the limit counts repository branches, not repositories.
searchstring

“search” defines the GitHub repository search query.

remark:

  • see https://docs.github.com/en/search-github/searching-on-github/searching-for-repositories for the query syntax.

example:

  • search: org:updatecli topic:updatecli
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: _

search is the only mandatory parameter. An empty query aborts the run with GitHub search query is required.

Apart from search, limit, and branch, every parameter above is passed through untouched to each generated github scm; refer to the "GitHub" page for what they do. Two consequences are worth spelling out:

  • directory is copied verbatim, so every discovered repository would be cloned into the same path. Leave it unset and let Updatecli derive one path per repository.

  • singleBranch, available on the github scm, has no equivalent here.

Search query

search is passed as-is to GitHub’s repository search. Useful qualifiers:

search: "org:myorg"                        # every repository in an organisation
search: "user:myuser"                      # every repository of a user
search: "topic:mytopic"                    # every repository carrying a topic
search: "org:myorg language:go"            # narrowed by language
search: "myrepo in:name"                   # by repository name

The full qualifier list is on GitHub Advanced Search.

Warning

Archived repositories are returned like any other, and Updatecli will try to push to them. Add archived:false to your query to leave them alone.

Updatecli paginates through all search results before applying limit, so a broad query costs the same number of API calls whatever the limit. Keep queries narrow.

If the query matches nothing, the entire run stops with no scm discovered for githubsearch scm "<id>" (this is a fatal error, not a skipped pipeline).

Branch selection

branch is a regular expression matched against every branch name of every discovered repository, not a branch name. It defaults to ^main$.

branch: "^main$"          # main only (default)
branch: "^main$|^v2$"     # main or v2
branch: "^release/"       # every release branch

Anchors matter. An unanchored expression such as main also matches maintenance, and . matches every branch in the repository, including every open dependabot/* branch.

Limit

limit caps the number of generated pipelines, that is repository/branch pairs - not the number of repositories. It defaults to 10; 0 means no cap.

A repository with three matching branches consumes three slots. With a permissive branch expression, limit: 3 can therefore expand into three pipelines all targeting the same repository on different branches, and never reach the second repository:

DEBUG: Processing GitHub repository: myorg/myrepo
* Repository: https://github.com/myorg/myrepo.git (branch: dependabot/github_actions/…)
* Repository: https://github.com/myorg/myrepo.git (branch: main)
* Repository: https://github.com/myorg/myrepo.git (branch: update-readme-references)

Repositories are consumed in the order GitHub returns them and branches in the order they are listed, so a limit that truncates the set gives you an arbitrary subset rather than a chosen one. Tighten branch and search instead of relying on limit to keep a run small.

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.

Working branch and commit message

Both work exactly as on the "GitHub" page: a working branch named <workingBranchPrefix><separator><branch><separator><pipelineID> and conventional commit messages driven by commitMessage.

The pipelineID component is derived from the manifest, not from the repository, so all copies of the manifest share it. Every discovered repository therefore ends up with an identically named working branch (convenient when you later need to find or clean up the branches an org-wide run created).

Note
commitMessage.title is deprecated and ignored. The commit title comes from the target name.

Example

This manifest bumps the Golang version across the repositories of the MyOrg organisation. githubsearch discovers them and keeps their main and v2 branches; autodiscovery then finds where Golang versions are declared (Go modules, Dockerfiles) while an explicit target covers GitHub Actions workflows.

Each discovered repository/branch pair gets its own working branch, its own squashed commit, and its own labelled pull request. With limit: 3, at most three of them are processed.

# updatecli.yaml
name: "Updatecli Golang"
pipelineid: "golang/version"

scms:
  default:
    kind: githubsearch
    spec:
      # exclude archived repositories, Updatecli would otherwise try to push to them
      search: "org:MyOrg archived:false"
      # maximum number of repository/branch pairs to process
      limit: 3
      # "branch" is a regular expression matched against every branch name
      branch: "^main$|^v2$"
      commitusingapi: true
      commitmessage:
        squash: true
        type: chore
        scope: deps
      user: myGitCommitUsername
      email: myGitCommitEmail

actions:
  default:
    kind: github/pullrequest
    scmid: default
    spec:
      labels:
        - dependencies
      title: "update Golang version"
      usetitleforautomerge: true

autodiscovery:
  scmid: default
  actionid: default
  groupby: all
  crawlers:
    golang:
      onlygoversion: true
      versionfilter:
        kind: "semver"
        pattern: "1.24.x"
    dockerfile:
      digest: true
      only:
        - images:
            - "registry.suse.com/bci/golang"
      versionfilter:
        kind: semver
        pattern: "1.24.x"

sources:
  golang:
    name: Get the latest Golang version
    kind: golang
    spec:
      versionfilter:
        kind: semver
        pattern: "1.24.x"

targets:
  github-action:
    name: 'deps(github-action): Bump Golang version to {{ source "golang" }}'
    kind: yaml
    scmid: default
    spec:
      engine: yamlpath
      files:
        - ".github/workflows/*"
      key: '$.jobs.build.steps[?(@.uses =~ /^actions\/setup-go/)].with.go-version'
      searchpattern: true