Skip to content
151 changes: 151 additions & 0 deletions docs/components/Bitbucket.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
title: "Bitbucket"
---

React to events in your Bitbucket repositories

## Triggers

<CardGrid>
<LinkCard title="On Push" href="#on-push" description="Listen to Bitbucket push events" />
</CardGrid>

## Instructions

To configure Bitbucket with SuperPlane:

- **API Token mode**:
- Go to **Atlassian Settings → Security → Create API token**.
- Select **Bitbucket** App.
- Create a token with admin:workspace:bitbucket scope.

- **Workspace Access Token mode**:
- Go to **Bitbucket Workspace Settings → Security → Access tokens**.
- Create a workspace access token.

- **Copy the token** and your workspace slug (for example: `my-workspace`) below.

<a id="on-push"></a>

## On Push

The On Push trigger starts a workflow execution when code is pushed to a Bitbucket repository.

### Use Cases

- **CI/CD automation**: Trigger builds and deployments on code pushes
- **Code quality checks**: Run linting and tests on every push
- **Notification workflows**: Send notifications when code is pushed

### Configuration

- **Repository**: Select the Bitbucket repository to monitor
- **Refs**: Configure which branches to monitor (e.g., `refs/heads/main`)

### Event Data

Each push event includes:
- **repository**: Repository information
- **push.changes**: Array of reference changes with new/old commit details
- **actor**: Information about who pushed

### Webhook Setup

This trigger automatically sets up a Bitbucket webhook when configured. The webhook is managed by SuperPlane and will be cleaned up when the trigger is removed.

### Example Data

```json
{
"actor": {
"display_name": "John Doe",
"links": {
"avatar": {
"href": "https://bitbucket.org/account/johndoe/avatar/"
},
"html": {
"href": "https://bitbucket.org/johndoe/"
}
},
"nickname": "johndoe",
"type": "user",
"uuid": "{d301aafa-d676-4ee0-a3f1-8b94c681feaa}"
},
"push": {
"changes": [
{
"closed": false,
"commits": [
{
"author": {
"raw": "John Doe \u003cjohn@example.com\u003e",
"type": "author"
},
"hash": "709d658dc5b6d6afcd46049c2f332ee3f515a67d",
"links": {
"html": {
"href": "https://bitbucket.org/my-workspace/my-repo/commits/709d658dc5b6d6afcd46049c2f332ee3f515a67d"
}
},
"message": "Add new feature\n",
"type": "commit"
}
],
"created": false,
"forced": false,
"new": {
"name": "main",
"target": {
"author": {
"raw": "John Doe \u003cjohn@example.com\u003e",
"type": "author",
"user": {
"display_name": "John Doe",
"type": "user",
"uuid": "{d301aafa-d676-4ee0-a3f1-8b94c681feaa}"
}
},
"date": "2024-01-15T10:30:00+00:00",
"hash": "709d658dc5b6d6afcd46049c2f332ee3f515a67d",
"links": {
"html": {
"href": "https://bitbucket.org/my-workspace/my-repo/commits/709d658dc5b6d6afcd46049c2f332ee3f515a67d"
}
},
"message": "Add new feature\n",
"type": "commit"
},
"type": "branch"
},
"old": {
"name": "main",
"target": {
"author": {
"raw": "John Doe \u003cjohn@example.com\u003e",
"type": "author"
},
"date": "2024-01-14T15:00:00+00:00",
"hash": "1e65c05c1d5171631d92438a13901ca7dae9618c",
"message": "Previous commit\n",
"type": "commit"
},
"type": "branch"
},
"truncated": false
}
]
},
"repository": {
"full_name": "my-workspace/my-repo",
"links": {
"html": {
"href": "https://bitbucket.org/my-workspace/my-repo"
}
},
"name": "my-repo",
"type": "repository",
"uuid": "{b7f10c3a-2a1e-4c36-af54-7e818f3b6e1d}"
}
}
```

188 changes: 188 additions & 0 deletions pkg/integrations/bitbucket/bitbucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package bitbucket

import (
"fmt"

"github.com/mitchellh/mapstructure"
"github.com/superplanehq/superplane/pkg/configuration"
"github.com/superplanehq/superplane/pkg/core"
"github.com/superplanehq/superplane/pkg/registry"
)

const (
AuthTypeAPIToken = "apiToken"
AuthTypeWorkspaceAccessToken = "workspaceAccessToken"

installationInstructions = `
To configure Bitbucket with SuperPlane:

- **API Token mode**:
- Go to **Atlassian Settings → Security → Create API token**.
- Select **Bitbucket** App.
- Create a token with admin:workspace:bitbucket scope.

- **Workspace Access Token mode**:
- Go to **Bitbucket Workspace Settings → Security → Access tokens**.
- Create a workspace access token.

- **Copy the token** and your workspace slug (for example: ` + "`my-workspace`" + `) below.
`
)

func init() {
registry.RegisterIntegrationWithWebhookHandler("bitbucket", &Bitbucket{}, &BitbucketWebhookHandler{})
}

type Bitbucket struct{}

type Configuration struct {
Workspace string `json:"workspace"`
AuthType string `json:"authType"`
Token *string `json:"token"`
Email *string `json:"email"`
}

type Metadata struct {
AuthType string `json:"authType" mapstructure:"authType"`
Workspace *WorkspaceMetadata `json:"workspace,omitempty" mapstructure:"workspace,omitempty"`
}

type WorkspaceMetadata struct {
UUID string `json:"uuid" mapstructure:"uuid"`
Name string `json:"name" mapstructure:"name"`
Slug string `json:"slug" mapstructure:"slug"`
}

func (b *Bitbucket) Name() string {
return "bitbucket"
}

func (b *Bitbucket) Label() string {
return "Bitbucket"
}

func (b *Bitbucket) Icon() string {
return "bitbucket"
}

func (b *Bitbucket) Description() string {
return "React to events in your Bitbucket repositories"
}

func (b *Bitbucket) Instructions() string {
return installationInstructions
}

func (b *Bitbucket) Configuration() []configuration.Field {
return []configuration.Field{
{
Name: "workspace",
Label: "Workspace",
Type: configuration.FieldTypeString,
Description: "Bitbucket workspace slug",
Placeholder: "e.g. my-workspace",
Required: true,
},
{
Name: "authType",
Label: "Authentication Type",
Type: configuration.FieldTypeSelect,
Required: true,
Description: "Bitbucket authentication type",
TypeOptions: &configuration.TypeOptions{
Select: &configuration.SelectTypeOptions{
Options: []configuration.FieldOption{
{Label: "API Token", Value: AuthTypeAPIToken},
{Label: "Workspace Access Token", Value: AuthTypeWorkspaceAccessToken},
},
},
},
},
{
Name: "token",
Label: "Token",
Type: configuration.FieldTypeString,
Sensitive: true,
Description: "The API token or workspace access token to use for authentication",
Required: true,
},
{
Name: "email",
Label: "Email",
Type: configuration.FieldTypeString,
Description: "Atlassian account email",
Required: true,
VisibilityConditions: []configuration.VisibilityCondition{
{Field: "authType", Values: []string{AuthTypeAPIToken}},
},
},
}
}

func (b *Bitbucket) Components() []core.Component {
return []core.Component{}
}

func (b *Bitbucket) Triggers() []core.Trigger {
return []core.Trigger{
&OnPush{},
}
}

func (b *Bitbucket) Cleanup(ctx core.IntegrationCleanupContext) error {
return nil
}

func (b *Bitbucket) Sync(ctx core.SyncContext) error {
config := Configuration{}
if err := mapstructure.Decode(ctx.Configuration, &config); err != nil {
return fmt.Errorf("failed to decode configuration: %w", err)
}

if config.Workspace == "" {
return fmt.Errorf("workspace is required")
}

if config.AuthType == "" {
return fmt.Errorf("authType is required")
}

if config.AuthType != AuthTypeAPIToken && config.AuthType != AuthTypeWorkspaceAccessToken {
return fmt.Errorf("authType %s is not supported", config.AuthType)
}

client, err := NewClient(config.AuthType, ctx.HTTP, ctx.Integration)
if err != nil {
return fmt.Errorf("error creating client: %w", err)
}

workspace, err := client.GetWorkspace(config.Workspace)
if err != nil {
return fmt.Errorf("error getting workspace: %w", err)
}

ctx.Integration.SetMetadata(Metadata{
AuthType: config.AuthType,
Workspace: &WorkspaceMetadata{
UUID: workspace.UUID,
Name: workspace.Name,
Slug: workspace.Slug,
},
})

ctx.Integration.Ready()

return nil
}

func (b *Bitbucket) HandleRequest(ctx core.HTTPRequestContext) {
// no-op
}

func (b *Bitbucket) Actions() []core.Action {
return []core.Action{}
}

func (b *Bitbucket) HandleAction(ctx core.IntegrationActionContext) error {
return nil
}
Loading