Skip to content
Author with AI

<GitPullRequest>

The <GitPullRequest> block commits the changes made in a repository cloned by <GitClone>, pushes them to a new branch, and opens a GitHub pull request or a GitLab merge request. One block covers both providers.

Pair it with <GitAuth> and <GitClone>. The provider comes from the linked <GitAuth> block, so no provider prop is needed:

<GitAuth
id="git-auth"
title="Connect to Git"
/>
<GitClone
id="clone-repo"
gitAuthId="git-auth"
title="Clone Repository"
prefilledUrl="https://github.com/acme-corp/infrastructure"
/>
<GitPullRequest
id="create-pr"
gitAuthId="git-auth"
title="Open Pull Request"
description="Create a PR with the changes made in this runbook"
/>

<GitPullRequest> determines which provider (GitHub or GitLab) to talk to in this order:

  1. An explicit provider prop, if set.
  2. The GIT_PROVIDER output of the block referenced by gitAuthId (or githubAuthId).
  3. The host of the cloned repository’s remote URL. github.com and *.ghe.com tenants are recognized as GitHub and gitlab.com as GitLab. A GitHub Enterprise Server or self-managed GitLab host is recognized only through the linked auth block.
  4. Otherwise, github.

A merge request is opened on the GitLab instance that the repository’s origin remote points at, whether that is gitlab.com or a self-managed host:

  • An https:// remote keeps its port.
  • An SSH remote (git@gitlab.example.com:group/repo.git, gitlab@gitlab.example.com:group/repo.git or ssh://git@gitlab.example.com:2222/group/repo.git) maps to https://gitlab.example.com. The port in an SSH URL belongs to the SSH server, not the web server.
  • A plain http:// remote is refused. The GitLab token is sent only over HTTPS (see GitHub Enterprise hosts below).

The block never falls back to gitlab.com. If the checkout has no origin remote, or its URL has no host, the block fails before your GitLab token is sent anywhere.

You can pre-populate the PR/MR title, description, labels, branch name, and commit message. Users can still edit these values before creating it.

<GitPullRequest
id="create-pr"
gitAuthId="git-auth"
prefilledPullRequestTitle="Add VPC module configuration"
prefilledPullRequestDescription="## Changes\n- Added VPC module\n- Configured NAT gateway"
prefilledPullRequestLabels={["enhancement", "terraform"]}
prefilledBranchName="feature/add-vpc"
prefilledCommitMessage="Add VPC module configuration"
/>

The prefilledPullRequestTitle, prefilledPullRequestDescription, prefilledBranchName, and prefilledCommitMessage props support template expressions that reference inputs and outputs from other blocks. Escape sequences like \n are converted to real newlines, which is useful for multi-line descriptions:

<GitPullRequest
id="create-pr"
gitAuthId="git-auth"
prefilledPullRequestTitle="Add {{ .outputs.config.MODULE_NAME }} module"
prefilledBranchName="feature/{{ .outputs.config.MODULE_NAME }}"
/>

Template expressions are resolved in real-time as upstream blocks produce outputs. If the block references outputs from blocks that haven’t run yet, it displays a warning and disables the create button until all dependencies are satisfied.

Prop Type Required Description
id string Yes Unique block identifier. Used by downstream blocks to reference outputs.
title string No Display title for the block header. Supports inline markdown and template expressions. Defaults per provider (Create Pull Request / Create Merge Request).
description string No Description text below the title. Supports inline markdown and template expressions.
autoCollapse boolean No Folds the block down to its title once the pull or merge request is opened. Defaults to false. See Folding done blocks.
provider 'github' | 'gitlab' No Locks the provider. Left unset, the provider is derived as described in Provider detection. Write the value in lowercase. Any other value, such as "GitHub", makes the block fail to render.
inputsId string | string[] No Reference to one or more <Inputs> blocks by ID for template variable substitution. When multiple IDs are provided, variables are merged in order (later IDs override earlier ones).
gitAuthId string No Reference to a <GitAuth> block (either provider). The block waits for authentication to complete and uses its token/provider for this execution.
githubAuthId string No Reference to a <GitHubAuth> block. GitHub only. Prefer gitAuthId.
prefilledPullRequestTitle string No Pre-fills the title field. Supports template expressions.
prefilledPullRequestDescription string No Pre-fills the description field. Supports template expressions, markdown, and \n for newlines.
prefilledPullRequestLabels string[] No Pre-selects labels by name. Labels must exist in the repository.
prefilledBranchName string No Pre-fills the branch name. Supports template expressions. Defaults to runbook/<timestamp>.
prefilledCommitMessage string No Pre-fills the commit message field. Supports template expressions.

After a successful create, the block produces outputs that can be referenced by downstream blocks:

Output Description Example
PR_ID The pull request number, or the GitLab merge request iid 42
PR_URL The full URL of the created pull/merge request https://github.com/org/repo/pull/42

Pass an output to a later block’s script with its env prop:

<Command
id="notify"
title="Post PR Link"
env={{ PR_URL: "{{ .outputs.create_pr.PR_URL }}" }}
command='echo "PR created: $PR_URL"'
/>

After creating a PR/MR, the block shows a Git Push button. It runs git push -u origin <branch> for the PR/MR’s branch with the linked auth block’s token. It does not stage or commit anything, so use it to push commits made since the PR/MR was created, for example by a Command block that ran git commit. To commit uncommitted changes onto the open PR/MR, choose “create another” and enter its branch name. See Creating another PR/MR.

If creation fails after the branch was created (for example, the push is rejected or the API call fails), fix the cause and create again with the same branch name. The block picks up on the existing branch: it commits any new changes and pushes, then opens the PR/MR.

You can also retry under a new branch name. The new branch starts from the branch the failed attempt left checked out, so if that attempt’s push failed, its commits are pushed under the new name, along with any new changes.

If a local branch with that name already exists but isn’t checked out (for example, one left over from an earlier run), the block offers to delete it and retry. The delete is refused if the branch has commits that haven’t been pushed or merged; choose a new branch name instead.

The branch name can’t be the base branch or a protected name (main, master, develop, dev, staging, release, prod, production).

After a PR/MR is created, its branch stays checked out, and “create another” fills in a new branch name such as runbook/<timestamp>. What the next create does depends on the branch name and on whether anything changed since:

  • With a new name and new changes, the new branch starts from the open PR/MR’s branch, so the new PR/MR also contains the open one’s commits.
  • With a new name and no new changes, the create is refused with “Nothing to commit”. The open PR/MR’s commits are already on the remote, and a new PR/MR would only repeat them. Nothing is pushed, and the open PR/MR’s branch stays checked out.
  • With the open PR/MR’s branch name, the block picks up on that branch, commits any new changes and pushes them to it, so they become part of the open PR/MR, and then reports that the PR/MR already exists.

The block shows Git Push until you choose “create another”.

The block needs a <GitClone> block that has cloned or selected a repository, which the PR/MR is created against. With gitAuthId or githubAuthId, it also needs the auth block it names to have signed in. It checks both and shows an amber warning for whichever is missing. The create button stays disabled until both are met.

For authentication, the block waits for the __AUTHENTICATED output that the block referenced by gitAuthId or githubAuthId sets once it signs in, whichever way the user signed in. Until then, the block displays “Waiting for <provider> authentication” and links to the block to complete. Without gitAuthId or githubAuthId, the block doesn’t wait for an auth block. It creates the PR/MR with the session’s token for the provider, and fails if the session has none.

For the repository, the block uses the workspace’s active repository: the one selected in the workspace’s repository dropdown, which is the first one added, whether by a clone or a local checkout, until the user selects another. No prop picks a <GitClone> block. Until a <GitClone> block has added a repository to the workspace, the block displays “No repository available”. A <GitClone> block with showFileTree={false} doesn’t add its repository.

The block fetches available labels from the repository and presents them in a searchable multi-select dropdown. Labels can also be pre-selected using the prefilledPullRequestLabels prop.

On GitHub, labels are applied after the pull request opens. If applying them fails, the pull request is still created and the logs show a warning.

GitLab merge requests use the instance of the repository’s remote, as described above. On GitHub, the pull request is opened against the host of the cloned repository’s origin remote: github.com, a GitHub Enterprise Server host such as github.example.com, or a GHE.com tenant such as acme.ghe.com. The block uses that host’s API (https://api.github.com, https://<host>/api/v3, or https://api.<tenant>.ghe.com) and fetches labels from it.

That host must be the one the linked auth block authenticated to (its GITHUB_HOST output). If they differ, for example a repository cloned from github.example.com while the auth block signed in to github.com, the block fails with an error. Links to token settings shown by the block also follow the authenticated host.

For both providers, the token is sent only over HTTPS, and only to the host the linked auth block authenticated to (the GITHUB_HOST or GITLAB_HOST it set). Runbooks never assumes github.com or gitlab.com. The block fails before sending the token if origin is on another host, is a plain http:// URL, is missing, or names no host Runbooks can read (a local path, or an address it can’t parse). Point origin at the repository on your GitHub or GitLab host (an https:// URL or a git@<host>:<owner>/<repo>.git address) and try again.

<GitAuth
id="git-auth"
provider="github"
host="github.example.com"
/>
<GitClone
id="clone-repo"
gitAuthId="git-auth"
prefilledUrl="https://github.example.com/platform/infrastructure-live"
/>
<GitPullRequest
id="create-pr"
gitAuthId="git-auth"
title="Open Pull Request"
/>

See GitHub Enterprise support for configuring the host.

Two aliases lock <GitPullRequest> to a single provider:

<GitAuth
id="git-auth"
title="Authenticate to Git"
/>
<GitClone
id="clone-infra"
gitAuthId="git-auth"
title="Clone Infrastructure Repo"
prefilledUrl="https://github.com/acme-corp/infrastructure-live"
/>
<Command
id="make-changes"
title="Apply Configuration"
env={{ REPO_DIR: "{{ .outputs.clone_infra.clone_path }}" }}
command='echo "new_setting = true" >> "$REPO_DIR/config.hcl"'
/>
<GitPullRequest
id="open-pr"
gitAuthId="git-auth"
title="Open Pull Request"
prefilledPullRequestTitle="Update infrastructure configuration"
prefilledPullRequestLabels={["infrastructure"]}
prefilledCommitMessage="Update infrastructure configuration"
/>