GitHub, GitLab, Bitbucket, or Azure DevOps: Connecting Your Git Provider to Bunnyshell
Why Multi-VCS Support Is a Real Requirement, Not a Nice-to-Have
Every guide in this pillar so far — automated PR environments, webhook-triggered updates, ChatOps commands — depends on one thing working correctly first: Bunnyshell needs to receive events from wherever your code actually lives. For a team that standardized entirely on GitHub Cloud years ago, this is invisible infrastructure. For a team with a more mixed history — an older codebase still on self-hosted Bitbucket Server, newer services on GitHub, an enterprise mandate to use Azure DevOps — "does this even work with our setup" is a real, first question, not a hypothetical.
Bunnyshell supports GitHub, GitLab, Bitbucket, and Azure DevOps, including self-hosted GitLab and Bitbucket Server instances, specifically because the PR-environment automation pattern only has value if it works with the Git provider a team is actually using — not the one a vendor wishes they were using.
What "Connecting" Actually Means Mechanically
Regardless of provider, the integration does the same three things:
- Registers a webhook so push and pull-request/merge-request events reach Bunnyshell in near-real-time.
- Grants read access to repository content, so Bunnyshell can check out the correct branch/commit to build from.
- Optionally grants status-check or comment-posting permission, used for features like posting the ephemeral environment's URL back onto the PR, or receiving ChatOps commands as PR comments (see ChatOps for QA Teams).
None of these require write access to your repository's code. The permission scope is deliberately narrow — read the code, receive events, optionally comment — which matters for security review conversations with a platform or security team evaluating the integration.
Connecting GitHub
GitHub integration uses a GitHub App (rather than a personal OAuth token tied to one user), installed at the organization or repository level from GitHub's App marketplace flow. This is the recommended pattern over a personal access token because the integration's access doesn't disappear if the person who originally connected it leaves the company — it's tied to the organization's installation, not an individual's credentials.
Once installed, any repository the App has access to can be connected to a Bunnyshell project, and createEphemeralOnPr on a primary environment tied to that repository starts working immediately for new PRs.
Connecting GitLab (Cloud or Self-Hosted)
GitLab integration works via an OAuth application (cloud) or a equivalent registered application against your self-hosted instance's OAuth provider. For self-hosted GitLab, the key additional requirement is network reachability: Bunnyshell's webhook receiver needs to be able to reach your GitLab instance's API (for read operations), and your GitLab instance needs to be able to reach Bunnyshell's webhook endpoint (to deliver events) — which may mean a firewall or reverse-proxy configuration step your platform team owns, unlike GitLab.com where both directions are open by default.
Connecting Bitbucket (Cloud or Server)
Bitbucket Cloud uses an OAuth consumer registered at the workspace level. Bitbucket Server (self-hosted) uses a similar webhook-registration model to self-hosted GitLab — same network-reachability consideration applies.
Connecting Azure DevOps
Azure DevOps integration uses a service connection with a personal access token or Azure AD app registration, scoped to the specific Azure DevOps organization and project. Azure DevOps's permission model is somewhat more granular than the others by default (separate scopes for code read, build, and webhook management), so the connecting user needs the specific combination of scopes rather than a single "admin" toggle.
The Part That Doesn't Change Based on Provider
This is the important payoff of multi-VCS support: once any of the four providers is connected, everything covered elsewhere in this guide series works identically regardless of which one it is. A primary environment with createEphemeralOnPr enabled spawns an ephemeral environment on pull request open whether that pull request came from GitHub, a merge request from GitLab, or a pull request from Bitbucket/Azure DevOps — Bunnyshell normalizes the provider-specific event into the same internal action. The bns environments CLI commands, the ChatOps comment syntax, the webhook-triggered redeploy mechanism — none of it needs to know or care which provider originated the event.
This is a meaningful design property to be explicit about, because it means a team currently on GitHub does not build automation that quietly becomes GitHub-specific and needs to be rebuilt if the company later migrates to GitLab or gets acquired into an org standardized on Azure DevOps. The automation described throughout this pillar is provider-agnostic by construction, not by coincidence.
Handling a Mixed-Provider Organization
It's common enough to be worth addressing directly: some organizations genuinely have repositories split across providers — a legacy monolith on self-hosted Bitbucket Server, a newer set of microservices on GitHub. Bunnyshell supports connecting multiple providers to the same organization simultaneously, with individual projects/environments tracking whichever repository they actually live in. There's no requirement to consolidate onto a single provider before adopting PR-environment automation — the automation is applied per-repository connection, not per-organization.
Verifying the Connection Actually Works
After connecting a provider, the fastest verification is opening a real test PR against a repository whose primary environment has createEphemeralOnPr enabled, and confirming an ephemeral environment appears:
bns environments list --project <PROJECT_ID>Look for a new ephemeral type entry corresponding to the test PR's branch. If nothing appears within a minute or two of opening the PR, the most common causes are: the webhook wasn't actually registered (check the provider's webhook delivery log), the repository connected in Bunnyshell doesn't match the repository the PR was opened against, or the primary environment's ephemeral settings aren't actually enabled (bns environments show --id <PRIMARY_ID> will show the current settings).
Troubleshooting a Connection That Isn't Working
Webhooks appear registered, but no ephemeral environment is created on new PRs. Confirm the repository connected inside Bunnyshell actually matches the repository the PR was opened against — a surprisingly common cause is a project connected to a fork or a renamed repository, where the webhook fires correctly but points at metadata Bunnyshell no longer recognizes as linked to an active primary environment.
The integration was working, then stopped. OAuth tokens and App installations can be revoked from the provider side without Bunnyshell being notified in real time — a security review that rotates organization-wide tokens, an admin who removes an App installation while cleaning up unused integrations, or an expired self-hosted OAuth application are all realistic causes. Re-authorizing the connection from the Bunnyshell integration settings is the fix, and worth checking first before assuming the issue is anything more complex.
Self-hosted GitLab/Bitbucket Server webhook deliveries show as failed. This is almost always a network reachability issue in one direction or the other — confirm your self-hosted instance can reach Bunnyshell's webhook endpoint outbound (check for an egress firewall rule blocking it), and separately confirm Bunnyshell can reach your instance's API inbound if your setup requires that direction too. These are two independent checks; a fix to one direction does not imply the other is also fixed.
Azure DevOps: some operations work, others fail with a permissions error. Azure DevOps's more granular scope model (separate scopes for code read, build, and webhook management, as noted above) means a connection can be partially functional — capable of receiving webhooks but not reading repository content, for instance — if the connecting credential wasn't granted every scope needed. Reviewing the exact scopes on the service connection or PAT used, rather than assuming "it's connected" implies "it has full access," resolves this category of issue.
Migrating Between Providers
Occasionally a team migrates its entire codebase from one Git provider to another — GitHub to a self-hosted GitLab instance for compliance reasons, or the reverse during a consolidation after an acquisition. Because the PR-environment automation described throughout this pillar is provider-agnostic by design (as emphasized above), the migration path is: connect the new provider, re-point the relevant Bunnyshell projects at the repositories in their new home, and disconnect the old provider integration once the migration is confirmed complete. No changes to bunnyshell.yaml, no changes to how ChatOps commands work, no changes to webhook-triggered update behavior — the automation itself doesn't know or care which provider it's connected to, so a provider migration is a connection-configuration change, not a rebuild of the automation.
Repository-Level vs. Organization-Level Connections
A design decision worth making deliberately rather than defaulting into: should the Git provider integration be connected at the organization/workspace level (granting access to every repository, with individual repositories then opted in per Bunnyshell project) or at the individual repository level (a narrower grant, repeated per repository as needed)? GitHub's App-installation model supports both — an App can be installed org-wide or scoped to a specific list of repositories at install time. The organization-wide grant is more convenient as new repositories are added over time (no re-authorization needed per new repo), but represents a broader standing permission than a team with many repositories that should never have preview environments (internal tooling repos, documentation-only repos) might want to grant. For a security-conscious setup, scoping the App installation to explicitly the repositories that will actually use Bunnyshell's PR automation — and revisiting that list periodically as new repositories are created — is the more disciplined default, even though it means a small amount of repeated setup work compared to a one-time organization-wide grant.
Testing a Mixed-Provider Setup End to End
For an organization actually running services split across two providers (the legacy-Bitbucket, newer-GitHub scenario mentioned above), it's worth testing both integration paths independently before assuming the setup is complete — connecting GitHub and confirming ephemeral environments spawn correctly for a GitHub-hosted repository does not verify anything about the separate Bitbucket connection, since these are entirely independent integrations under the hood, sharing no configuration with each other beyond both reporting into the same Bunnyshell organization. Running the verification sequence described above (bns environments list after opening a test PR) once per connected provider, not just once overall, is the only way to be confident both halves of a mixed-provider setup are actually functioning rather than assuming success on one implies success on the other.
Handling an Organization-Wide Security Review
Security teams reviewing third-party integrations against a Git provider frequently ask a standard set of questions worth having answers ready for: what scopes does the integration hold (read repository content, manage webhooks, optionally post status checks/comments — never write access to code, as covered above), where are credentials for the integration stored (Bunnyshell's own backend, not distributed to individual developer machines), and what happens if the integration is compromised (an attacker with access to Bunnyshell's stored credentials for your organization could read repository content and register/modify webhooks, but could not push code or approve pull requests, since those permissions were never granted in the first place). Having this scope breakdown ready, rather than needing to reconstruct it under time pressure during a review, is a small amount of upfront documentation that meaningfully speeds up getting a security team's sign-off on adopting the integration.
Disconnecting a Provider Cleanly
The reverse operation — removing a Git provider integration, whether during a migration or simply decommissioning a project — deserves the same deliberateness as connecting one. Disconnecting revokes Bunnyshell's webhook registration and API access on the provider side, which means any primary environment still configured with createEphemeralOnPr pointed at that now-disconnected repository will stop spawning new ephemeral environments on new PRs, silently, from the moment of disconnection. Before disconnecting a provider integration that's actively backing live automation, confirm with the teams relying on it, and consider whether any already-running ephemeral environments spawned under the old connection should be explicitly cleaned up rather than left orphaned with no further lifecycle events able to reach them (since their originating webhook source no longer exists to fire close/merge events at all).
Keeping the Integration Healthy Long-Term
A Git provider integration, once working, tends to be forgotten about — which is fine until an organization-wide token rotation, a security review revoking unused App installations, or a provider-side policy change quietly breaks it without an obvious immediate symptom (new PRs simply stop getting ephemeral environments, which can go unnoticed for a while if PR volume on the affected repository is low). Treating this integration the same as any other piece of production-adjacent infrastructure — included in whatever periodic access review or integration audit a platform team already runs — is a small addition to an existing process rather than a new one, and catches this class of silent breakage well before someone stumbles onto it while trying to debug an unrelated problem.
A Quick Reference for What Happens After Connection
Once a provider is connected, everything else in this pillar follows automatically: Automated PR Environments for E2E Testing describes the create-deploy-test-destroy cycle the connection enables, Webhook-Triggered Environment Updates covers the push-driven redeploy mechanism this same connection powers, and ChatOps for QA Teams covers the comment-based control surface that rides on top of it. None of these require any additional provider-level configuration beyond what's described here.
Checklist
- Git provider integration installed with organization/workspace-level admin access
- Repository connected to the correct Bunnyshell project
- Primary environment's
createEphemeralOnPrconfirmed enabled (not assumed) - Test PR opened and ephemeral environment confirmed via
bns environments list - For self-hosted GitLab/Bitbucket Server: network reachability confirmed in both directions
Connect your Git provider and get PR environments working today.
14-day full-feature trial. No credit card required. Pay-as-you-go from $0.007/min per environment.
Frequently Asked Questions
Which Git providers does Bunnyshell support?
GitHub, GitLab, Bitbucket, and Azure DevOps, including self-hosted/on-premises instances of GitLab and Bitbucket Server, not only the cloud-hosted SaaS versions.
Does connecting a Git provider require organization admin access?
Yes, typically. Installing a GitHub App, authorizing a GitLab OAuth application, or registering webhooks on Bitbucket/Azure DevOps requires administrative permissions on the organization or project being connected, since it involves granting Bunnyshell webhook and (for private repos) read access.
Can I connect more than one Git provider to the same Bunnyshell organization?
Yes. It is common for organizations with a mixed codebase history (a legacy repo on Bitbucket, newer services on GitHub) to connect multiple providers simultaneously, with different projects or environments tracking different repositories.
What permissions does Bunnyshell actually need from my Git provider?
At minimum, read access to repository content (to check out code for builds) and webhook management (to receive push/PR events). It does not need write access to your repository unless you specifically use a feature that posts status checks or PR comments back, which uses a narrower, separate permission scope.
Does self-hosted GitLab or Bitbucket Server work the same way as the cloud versions?
The integration model is the same — webhook registration and API access for PR/MR metadata — but self-hosted instances need to be reachable from Bunnyshell's webhook receiver, which may require network/firewall configuration your platform team needs to set up, unlike SaaS providers which are reachable by default.