Documentation / Infrastructure runs
Running from a repository
Connect a workspace to a GitHub repository: a plan on every pull request, with a commit status and a comment, the Details link, and merging to apply.
Connect a workspace to a GitHub repository and your runs start from Git rather than from your terminal. A pull request gets a plan that can never apply, with the result on the pull request itself. Merging it starts the real run, and that waits for somebody to apply it, unless you have told the workspace not to wait.
Everything on this page was walked on production against a real repository. The examples are what that repository's pull requests showed.
The workspace reads your repository through the same GitHub App installation that runs your CI jobs, so connect that first. See connect your account.
Then, on Settings → Version control, an owner or an admin presses Use your GitHub installation in the Source control for Terraform section. A GitHub App row appears in the list there. Terraform can now see the repositories the installation was given, and no others. To give it another repository, add the repository to the installation on GitHub.
GitLab and Forgejo are not available yet. The section accepts an access token for either, but neither has been run end to end on production, so we do not offer them as a supported route. This page walks the GitHub route.
For a new workspace, choose the connection under Repository on Terraform → New workspace, then pick the Repository to connect. For an existing one, open the workspace's Settings tab, then Version control: choose the connection, type or pick the Repository, and press Connect repository.
In both places Branch is optional. Left empty, the workspace follows the repository's default branch. The configuration is read from the repository's root unless you set a Working directory on the same tab.
A workspace that runs from a repository has no cloud block to write. The configuration in the repository is the configuration it runs.
Once the repository is connected, the Version control card asks What starts a run:
Every push: any push to the branch starts a run. This is the default.
Only when matching files change: glob patterns, one per line.
Only when files under these paths change: directories, one per line. The working directory always counts as well.
When a matching tag is pushed: a regular expression for tag names. Pushes to branches then start nothing.
Below them, Plan pull requests decides whether a pull request gets a plan. It is on unless you turn it off. The plan is made only for a pull request opened by somebody with write access to the repository.
Opening a pull request, and every push to it afterwards, starts a speculative plan: a plan-only run that cannot be applied, whatever anyone clicks. Like any plan-only run, it does not wait in the workspace's queue behind other runs.
The plan reports on the pull request's latest commit as a commit status named otf/ followed by the workspace's name. It is pending while the run is queued and planning, then success, with the plan's counts of resources to add, change and destroy. This is what the walk's pull request showed, for a workspace named vcs-canary:
otf/vcs-canary pending
otf/vcs-canary success planned: +1/~0/−0A second status sits beside it, named the same with /opentofu on the end: the OpenTofu compatibility check of the same commit. It is set before the plan starts and passes or fails on its own. On the walk's pull request, and on its merge commit, it read:
otf/vcs-canary/opentofu success OpenTofu 1.13.1: compatible (1 file checked)A run that errors, is cancelled or is discarded sets the status to error. Its Details link, below, says why.
With cost estimation turned on, the description starts with the monthly change in your cloud bill and how many resources could not be priced, then the counts:
otf/vcs-canary success cost +$…/mo (2 not estimated); planned: +3/~0/−0The figure is left out here because these pages quote no prices. On your pull request it is the estimate for your plan.
The same run writes a comment on the pull request, one per workspace. On a private repository, the one from the walk read:
Plan finished in workspace vcs-canary
Commit 385e73bcc555 · View run
Resources: 1 to add, 0 to change, 0 to destroy.
Outputs: 1 to add, 0 to change, 0 to remove.
▸ Plan output
Updated in place on every push. Set RUNNERS_PR_COMMENT on the workspace to
full, summary or off to change what is shown here.Plan output expands to the plan as the run printed it. With cost estimation on, an Estimated cloud cost line sits above the resource counts.
The comment is updated in place on every push, so a long pull request carries one comment per workspace, not one per commit. A plan too long for a GitHub comment is cut at a line, and the comment says how much it is showing and links to the full plan on the run page.
What it shows is up to the workspace, through an environment variable called RUNNERS_PR_COMMENT, set on its Variables tab or in a variable set:
RUNNERS_PR_COMMENT | the comment shows |
|---|---|
full | the counts, a link to the run, and the plan output |
summary | the counts and a link to the run, without the plan output |
off | one line saying plan comments are off for this workspace |
Unset, a private repository gets full and a public repository gets summary, so a plan is never published to the internet unless you ask for it. The comment says when that is why the plan output is missing.
With a policy set covering the workspace, the pull request's plan is checked against it before the run ends. The timeline shows that stage as Checking policies. The policies can come from the same repository: on the walk below they came from the repository's policies directory.
A pull request's plan can never be applied, so when a mandatory policy fails, the run ends in an error. The status says which policy stopped it:
otf/vcs-canary pending
otf/vcs-canary error a mandatory policy failed: no-new-terraform-dataThe plan comment is headed Policy check failed and lists every failing policy with its set, above the counts and the plan. On the walk's pull request it read:
Policy check failed in workspace vcs-canary
Commit f952be680204 · View run
A mandatory policy failed, so this run stops here. The plan itself finished;
the policies below did not pass it.
- no-new-terraform-data in policy set r1424-repo-guardrails-050239 · failed · mandatory
RUN-1424 docs walk: terraform_data.tick may not be created
Every policy result is on the run page.
Resources: 1 to add, 0 to change, 0 to destroy.The indented line is the message your Rego returned, shown when the comment shows the plan output (RUNNERS_PR_COMMENT is full). Messages are masked the same way the plan is. The Details link opens the run with its OPA policy checks section, which names the set, the failing policy, its enforcement level and the same message.
Advisory failures are reported there and do not stop the run. On a run that could apply, such as the one a merge starts, a mandatory failure in a set that allows overrides holds the run instead of ending it. Its status stays pending, described as a mandatory policy failed: awaiting an override, until somebody permitted overrides it or the run is discarded.
The status's Details link, and the comment's View run, point at tf.runners.io/app/runs/ followed by the run's id. That address forwards to the run on www.runners.io, so the click lands on the run screen in the dashboard: its status, its plan, and its timeline.
If you are not signed in, you are asked to sign in and then taken to the run. Somebody signed in to a different organisation gets the not-found page, and nothing of the run.
A merge is a push to the branch the workspace follows, so it starts a run: a real one this time, built from the merge commit.
By default the run stops when its plan has finished and waits for a person. Its commit status on the merge commit stays pending, and its run screen says it needs approval. Apply asks "Apply this plan? It will change your infrastructure." and Yes, apply applies it. Discard throws the plan away instead. Both are there for anybody whose access to the workspace lets them apply. When the apply finishes, the status is success with what was applied. From the walk's merge commit:
otf/vcs-canary pending
otf/vcs-canary success applied: +1/~0/−0There is no comment on a merge commit: comments are for pull requests.
To apply without anyone approving, tick Apply successful plans automatically on the workspace's Settings tab. A successful plan then changes your infrastructure without anyone approving it, which is exactly what the setting says beside it.
A notification channel on Settings → Notifications hears runs started from a repository the same way it hears every other run. During the walk, a Slack channel on the workspace was sent these, in order:
| when | the message's title |
|---|---|
| the pull request's plan finished | Terraform plan finished: vcs-canary |
| the merge's plan was waiting for approval | Terraform run needs attention: vcs-canary |
| the apply finished | Terraform run applied: vcs-canary |
Each links to the run on the dashboard. A speculative plan is titled a Terraform plan and a run that may change something a Terraform run, so a channel can tell them apart.
Under the title, a finished speculative plan's Status says what it would have changed, in the run screen's own words. For the walk's pull request, whose plan added one resource, it read Plan finished: 1 to add / 0 to change / 0 to destroy (speculative, cannot be applied).
A plan with nothing to change says so in the title instead: Terraform plan finished with nothing to change.
A speculative plan is a run, and its minutes are run-minutes, the same as a plan you start from the CLI. So is the run a merge starts. The rates are on pricing.