Github Search
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
| Name | Type | Description | Required |
|---|---|---|---|
| app | object | “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: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation | |
| clientid | string | ClientID represents the GitHub App client ID | |
| expirationtime | string | 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) | |
| installationid | string | InstallationID represents the GitHub App installation ID
It is the same ID that you can find in the GitHub endpoint:
https://github.com/settings/installation/ | |
| privatekey | string | PrivateKey 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 | |
| privatekeypath | string | PrivateKeyPath 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 | |
| branch | string | “branch” defines the git branch to work on. compatible:
default: ^main$ remark: depending on which resource references the GitHub scm, the behavior will be different. If the scm is linked to a source or a condition (using scmid), the branch will be used to retrieve file(s) from that branch. If the scm is linked to target then Updatecli creates a new “working branch” based on the branch value.
The working branch created by Updatecli looks like “updatecli_ | |
| commitmessage | object | “commitMessage” is used to generate the final commit message. compatible:
remark: it’s worth mentioning that the commit message settings is applied to all targets linked to the same scm. | |
| body | string | body defines the commit body of the commit message as defined by the conventional commit specification. More information on -> https://www.conventionalcommits.org/en/ default: none | |
| deprecatedtitle | string | DeprecatedTitle is deprecated and will be ignored. The commit title is now always generated from the target name or description. | |
| footers | string | footers defines the footer of the commit message as defined by the conventional commit specification. More information on -> https://www.conventionalcommits.org/en/ default: none | |
| hidecredit | boolean | hideCredit defines if updatecli credits should be displayed inside commit message body please consider sponsoring the Updatecli project if you want to disable credits. -> https://github.com/updatecli/updatecli default: false | |
| scope | string | scope defines the scope of the commit message as defined by the conventional commit specification. More information on -> https://www.conventionalcommits.org/en/ default: none | |
| squash | boolean | squash defines if the commit should be squashed default: false important: if squash is set to true, then it’s highly recommended to set the commit body to a meaningful value as all other commit information will be lost during the squash operation. if body is not set, then the commit title/message will be generated based on the most recent commit message of the squashed commits. The commit title is always generated from the target name or description. | |
| title | string | Title is the parsed commit message title (not configurable via YAML). The title is automatically generated from the target name or description. | |
| type | string | type defines the type of commit message such as “chore”, “fix”, “feat”, etc. as defined by the conventional commit specification. More information on -> https://www.conventionalcommits.org/en/ default:
| |
| commitusingapi | boolean | “commitUsingApi” defines if Updatecli should use GitHub GraphQL API to create the commit.
When set to compatible:
default: false | |
| depth | integer | Depth defines the depth used when cloning the git repository. Default: disabled (full clone) Remark: When using a shallow clone (depth greater than 0), Updatecli is not able to retrieve the full git history. This may cause some issues when Updatecli tries to push changes to the remote repository. In that case, you may need to set the force option to true to force push changes to the remote repository. | |
| directory | string | “directory” defines the local path where the git repository is cloned. compatible:
remark: Unless you know what you are doing, it is recommended to use the default value. The reason is that Updatecli may automatically clean up the directory after a pipeline execution. default:
The default value is based on your local temporary directory like: (on Linux)
/tmp/updatecli/github/ | |
| string | “email” defines the email used to commit changes. compatible:
default: default set to your global git configuration | ||
| force | boolean | “force” is used during the git push phase to run compatible:
default: true remark: When force is set to true, Updatecli also recreates the working branches that diverged from their base branch. | |
| gpg | object | “gpg” specifies the GPG key and passphrased used for commit signing compatible:
| |
| passphrase | string | passphrase defines the gpg passphrase used to sign the commit message | |
| signingkey | string | signingKey defines the gpg key used to sign the commit message default: none | |
| limit | integer | Limit defines the maximum number of repositories to return from the search query. compatible:
default: 10 remark: If limit is set to 0, all repositories matching the search query will be returned. | |
| search | string | Search defines the GitHub repository search query. compatible:
remark: For more information about the search query syntax, please refer to the following documentation: https://docs.githubz.com/en/search-github/searching-on-github/searching-for-repositories | |
| submodules | boolean | “submodules” defines if Updatecli should checkout submodules. compatible:
default: true | |
| token | string | “token” specifies the credential used to authenticate with GitHub API. compatible:
remark: A token is a sensitive information, it’s recommended to not set this value directly in the configuration file but to use an environment variable or a SOPS file. The value can be set to or | |
| url | string | “url” specifies the default github url in case of GitHub enterprise compatible:
default: github.com | |
| user | string | “user” specifies the user associated with new git commit messages created by Updatecli compatible:
| |
| username | string | “username” specifies the username used to authenticate with GitHub API. compatible:
remark: the token is usually enough to authenticate with GitHub API. Needed when working with GitHub private repositories. | |
| workingbranch | boolean | “workingBranch” defines if Updatecli should use a temporary branch to work on.
If set to compatible:
default: true | |
| workingbranchprefix | string | WorkingBranchPrefix defines the prefix used to create a working branch. compatible:
default: updatecli remark: A working branch is composed of three components:
If WorkingBranchPrefix is set to ‘’, then
the working branch will look like “ | |
| workingbranchseparator | string | WorkingBranchSeparator defines the separator used to create a working branch. compatible:
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:
directoryis 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 thegithubscm, 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 nameThe 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 |
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 branchAnchors 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 IDUPDATECLI_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 AppUPDATECLI_GITHUB_APP_EXPIRATION_TIME: Optional token lifetime in seconds. Defaults to3600(one hour), the minimum accepted value is600
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 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 |
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 TokenUPDATECLI_GITHUB_USERNAME: Your GitHub username. Optional; Updatecli usesoauth2when 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:
UPDATECLI_GITHUB_TOKENenvironment variableUPDATECLI_GITHUB_APP_*environment variablesspec.tokenin the manifestspec.appin the manifestGITHUB_TOKENenvironment 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 |
|
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 foundFurther 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