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

== Description

`githubsearch` is not an scm you clone from - it is a *generator*. Before anything else runs, Updatecli sends your query to the link:https://docs.github.com/en/search-github/searching-on-github/searching-for-repositories[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 link:/docs/plugins/scm/github/[`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 link:/docs/plugins/actions/github/["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

{{< resourceparameters "scms" "githubsearch" >}}

`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 link:/docs/plugins/scm/github/["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:

[source,yaml]
----
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 link:https://github.com/search/advanced[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$`.

[source,yaml]
----
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:

[source,text]
----
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

include::content/en/docs/plugins/_githubAuth.adoc[]

=== Working branch and commit message

Both work exactly as on the link:/docs/plugins/scm/github/["GitHub" page]: a working branch named `<workingBranchPrefix><separator><branch><separator><pipelineID>` and link:https://www.conventionalcommits.org/[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.

[source,yaml]
----
# updatecli.yaml
{{<include "assets/code_example/docs/plugins/scm/githubsearch/updatecli.d/commitmessage.yaml">}}
----
