Skip to content

Commit

Permalink
Add support for Bitbucket Self-Hosted URL (#118)
Browse files Browse the repository at this point in the history
* feat: creates new config to set a BitbucketSelfHostedUrl

* feat: creates new plugin method to get the bitbucket baseURL and replaces the locations where the url is used

* chore: renaming and refactoring regarding PR review

* feat: adding docker-compose setting up bitbucket server

* feat: adding support for Apple M1 in the build

* feat: adds the API Self-Hosted URL

* feat: adds the code to check for the Bitbucket API Self Hosted URL

* feat: refactor of the plugin to be less repetitive on getting the configuration

* feat: refactor to get back to the shortcut string parameters

* test: adding tests for the new methods

* add gitpod files

* feat: adding a verification for the bitbucket URL if it's valid

* feat: adding conditionals to initialize oauth based on bitbucket server configs

* feat: PR review

* fix: fix lint

---------

Co-authored-by: Michael Kochell <[email protected]>
  • Loading branch information
panoramix360 and mickmister authored Oct 10, 2023
1 parent 84a4030 commit 3be0785
Show file tree
Hide file tree
Showing 17 changed files with 263 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitpod/command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker compose up
1 change: 1 addition & 0 deletions .gitpod/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker compose pull
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ ifneq ($(wildcard build/custom.mk),)
include build/custom.mk
endif

ifneq ($(MM_DEBUG),)
GO_BUILD_GCFLAGS = -gcflags "all=-N -l"
else
GO_BUILD_GCFLAGS =
endif

## Checks the code style, tests, builds and bundles the plugin.
.PHONY: all
all: check-style test dist
Expand Down Expand Up @@ -69,9 +75,10 @@ ifeq ($(MM_DEBUG),)
else
$(info DEBUG mode is on; to disable, unset MM_DEBUG)

cd server && env GOOS=darwin GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -o dist/plugin-darwin-amd64;
cd server && env GOOS=linux GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -o dist/plugin-linux-amd64;
cd server && env GOOS=windows GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -gcflags "all=-N -l" -o dist/plugin-windows-amd64.exe;
cd server && env GOOS=darwin GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) $(GO_BUILD_GCFLAGS) -o dist/plugin-darwin-amd64;
cd server && env GOOS=linux GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) $(GO_BUILD_GCFLAGS) -o dist/plugin-linux-amd64;
cd server && env GOOS=darwin GOARCH=arm64 $(GO) build $(GO_BUILD_FLAGS) $(GO_BUILD_GCFLAGS) -o dist/plugin-darwin-arm64;
cd server && env GOOS=windows GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) $(GO_BUILD_GCFLAGS) -o dist/plugin-windows-amd64.exe;
endif
endif

Expand Down
14 changes: 14 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: '3.7'

services:
bitbucket:
container_name: mattermost-bitbucket
image: atlassian/bitbucket:latest # It is recommended to use the bitbucket image instead of bitbucket-server since it's deprecated
ports:
- "7990:7990"
- "7999:7999"
volumes:
- bitbucket-data:/var/atlassian/application-data/bitbucket

volumes:
bitbucket-data:
17 changes: 17 additions & 0 deletions plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"executables": {
"linux-amd64": "server/dist/plugin-linux-amd64",
"darwin-amd64": "server/dist/plugin-darwin-amd64",
"darwin-arm64": "server/dist/plugin-darwin-arm64",
"windows-amd64": "server/dist/plugin-windows-amd64.exe"
},
"executable": ""
Expand Down Expand Up @@ -62,6 +63,22 @@
"help_text": "(Optional) Set to lock the plugin to a single Bitbucket organization.",
"placeholder": "",
"default": null
},
{
"key": "BitbucketSelfHostedURL",
"display_name": "Bitbucket Self-hosted URL",
"type": "text",
"help_text": "If using Bitbucket Server instead of Bitbucket Cloud, please set this value to your BitBucket server's URL.",
"placeholder": "",
"default": null
},
{
"key": "BitbucketAPISelfHostedURL",
"display_name": "Bitbucket API Self-hosted URL",
"type": "text",
"help_text": "If using Bitbucket Server instead of Bitbucket Cloud, please set this value to your BitBucket API server's URL.",
"placeholder": "",
"default": null
}
]
}
Expand Down
5 changes: 2 additions & 3 deletions server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"golang.org/x/oauth2"

"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
)

const (
Expand Down Expand Up @@ -155,7 +154,7 @@ func checkPluginRequest(next http.HandlerFunc) http.HandlerFunc {
}
}

func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
func (p *Plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
config := p.getConfiguration()

if err := config.IsValid(); err != nil {
Expand Down Expand Up @@ -247,7 +246,7 @@ func (p *Plugin) completeConnectUserToBitbucket(w http.ResponseWriter, r *http.R
_ = httpResponse.Body.Close()
}
if err != nil {
p.API.LogError("Error converting authorization code int token", "err", err.Error())
p.API.LogError("Error while trying to get users from bitbucket", "err", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
Expand Down
4 changes: 2 additions & 2 deletions server/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestPlugin_ServeHTTP(t *testing.T) {
req := test.httpTest.CreateHTTPRequest(test.request)
req.Header.Add("Mattermost-User-ID", test.userID)
rr := httptest.NewRecorder()
p.ServeHTTP(&plugin.Context{}, rr, req)
p.ServeHTTP(rr, req)
test.httpTest.CompareHTTPResponse(rr, test.expectedResponse)
})
}
Expand Down Expand Up @@ -122,7 +122,7 @@ func TestGetToken(t *testing.T) {
req := test.httpTest.CreateHTTPRequest(test.request)
rr := httptest.NewRecorder()

p.ServeHTTP(test.context, rr, req)
p.ServeHTTP(rr, req)

test.httpTest.CompareHTTPResponse(rr, test.expectedResponse)
})
Expand Down
7 changes: 4 additions & 3 deletions server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ func (p *Plugin) handleSubscribe(_ *plugin.Context, args *model.CommandArgs, par

ctx := context.Background()
bitbucketClient := p.bitbucketConnect(*userInfo.Token)
owner, repo := parseOwnerAndRepo(parameters[0], BitbucketBaseURL)
bitbucketURL := p.getBitbucketBaseURL()
owner, repo := parseOwnerAndRepo(parameters[0], bitbucketURL)
previousSubscribedEvents, err := p.findSubscriptionsEvents(args.ChannelId, owner, repo)
if err != nil {
return err.Error()
Expand All @@ -243,7 +244,7 @@ func (p *Plugin) handleSubscribe(_ *plugin.Context, args *model.CommandArgs, par
return err.Error()
}

repoLink := fmt.Sprintf("%s%s/%s", p.getBaseURL(), owner, repo)
repoLink := fmt.Sprintf("%s%s/%s", bitbucketURL, owner, repo)

msg := fmt.Sprintf("Successfully subscribed to [%s/%s](%s) with events: %s", owner, repo, repoLink, formattedString(features))
if previousSubscribedEvents != "" {
Expand Down Expand Up @@ -319,7 +320,7 @@ func (p *Plugin) handleMe(_ *plugin.Context, _ *model.CommandArgs, _ []string, u
return text
}

func (p *Plugin) handleHelp(_ *plugin.Context, _ *model.CommandArgs, _ []string, userInfo *BitbucketUserInfo) string {
func (p *Plugin) handleHelp(_ *plugin.Context, _ *model.CommandArgs, _ []string, _ *BitbucketUserInfo) string {
message := fmt.Sprintf("#### Welcome to the Mattermost Bitbucket Plugin!\n" +
"##### Daily Reminders\n" +
"The first time you log in each day, you will get a post right here letting you know what messages you need to read and what pull requests are awaiting your review.\n" +
Expand Down
31 changes: 31 additions & 0 deletions server/configuration.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"net/url"
"reflect"

"github.com/pkg/errors"
Expand All @@ -21,6 +22,8 @@ type Configuration struct {
BitbucketOrg string
BitbucketOAuthClientID string
BitbucketOAuthClientSecret string
BitbucketSelfHostedURL string
BitbucketAPISelfHostedURL string
WebhookSecret string
EncryptionKey string
}
Expand Down Expand Up @@ -49,9 +52,37 @@ func (c *Configuration) IsValid() error {
if c.WebhookSecret == "" {
return errors.New("must have a webhook secret")
}

if c.BitbucketSelfHostedURL != "" && !c.IsValidURL(c.BitbucketSelfHostedURL) {
return errors.New("BitbucketSelfHostedURL must be a valid URL")
}

if c.BitbucketAPISelfHostedURL != "" && !c.IsValidURL(c.BitbucketAPISelfHostedURL) {
return errors.New("BitbucketAPISelfHostedURL must be a valid URL")
}
return nil
}

// IsValidURL checks if an URL passed is valid
func (c *Configuration) IsValidURL(toTest string) bool {
_, err := url.ParseRequestURI(toTest)
if err != nil {
return false
}

u, err := url.Parse(toTest)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}

return true
}

// IsBitbucketSelfHosted checks if we are dealing with self-hosted bitbucket
func (c *Configuration) IsBitbucketSelfHosted() bool {
return c.BitbucketSelfHostedURL != "" && c.BitbucketAPISelfHostedURL != ""
}

// getConfiguration retrieves the active Configuration under lock, making it safe to use
// concurrently. The active Configuration may change underneath the client of this method, but
// the struct returned by this API call is considered immutable.
Expand Down
17 changes: 17 additions & 0 deletions server/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const manifestStr = `
"server": {
"executables": {
"darwin-amd64": "server/dist/plugin-darwin-amd64",
"darwin-arm64": "server/dist/plugin-darwin-arm64",
"linux-amd64": "server/dist/plugin-linux-amd64",
"windows-amd64": "server/dist/plugin-windows-amd64.exe"
},
Expand Down Expand Up @@ -76,6 +77,22 @@ const manifestStr = `
"help_text": "(Optional) Set to lock the plugin to a single Bitbucket organization.",
"placeholder": "",
"default": null
},
{
"key": "BitbucketSelfHostedURL",
"display_name": "Bitbucket Self-hosted URL",
"type": "text",
"help_text": "If using Bitbucket Server instead of Bitbucket Cloud, please set this value to your BitBucket server's URL.",
"placeholder": "",
"default": null
},
{
"key": "BitbucketAPISelfHostedURL",
"display_name": "Bitbucket API Self-hosted URL",
"type": "text",
"help_text": "If using Bitbucket Server instead of Bitbucket Cloud, please set this value to your BitBucket API server's URL.",
"placeholder": "",
"default": null
}
]
}
Expand Down
Loading

0 comments on commit 3be0785

Please sign in to comment.