Skip to content

Commit 02ffb8f

Browse files
committed
Issue #65: Added support for Data Center
1 parent 8944412 commit 02ffb8f

File tree

6 files changed

+47
-7
lines changed

6 files changed

+47
-7
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ You can also pass the `--progress` flag to display a progress bar when upload/do
181181

182182
By default, the password or client secret is stored in the vault of the operating system (Windows Credential Manager, macOS Keychain, or Linux Secret Service). You can pass the `--no-vault` flag to disable this feature and store the password or client secret in plain text in the configuration file. This is not recommended, but can be useful for testing purposes.
183183

184+
To connect to a Bitbucket Data Center, you can pass the `--host` flag to set the host of the Bitbucket instance (do not provide any host when connecting to bitbucket.org). For example:
185+
186+
```bash
187+
bb profile create \
188+
--name myprofile \
189+
--host bitbucket.mycompany.com \
190+
--client-id <your-client-id> \
191+
--client-secret <your-client-secret> \
192+
--callback-port 8080
193+
```
194+
184195
Profiles support the following authentications:
185196

186197
- [OAuth 2.0 with Authorization Code Grant](https://developer.atlassian.com/cloud/bitbucket/rest/intro/#1--authorization-code-grant--4-1-) with the `--client-id`, `--client-secret`, and `--callback-port` flags.

cmd/profile/create.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package profile
22

33
import (
44
"fmt"
5+
"net/url"
56
"os"
67
"path/filepath"
78
"runtime"
@@ -24,6 +25,7 @@ var createCmd = &cobra.Command{
2425

2526
var createOptions struct {
2627
Profile
28+
Host string
2729
DefaultWorkspace *flags.EnumFlag
2830
DefaultProject *flags.EnumFlag
2931
OutputFormat *flags.EnumFlag
@@ -45,6 +47,7 @@ func init() {
4547
createCmd.Flags().StringVar(&createOptions.VaultKey, "vault-key", "bitbucket-cli", "Vault key to use for storing credentials. Default is bitbucket-cli. On Windows, the Windows Credential Manager will be used, On Linux and macOS, the system keychain will be used.")
4648
}
4749
createCmd.Flags().BoolVar(&createOptions.NoVault, "no-vault", false, "Do not store credentials in the vault. This will store them in plain text in the configuration file.")
50+
createCmd.Flags().StringVar(&createOptions.Host, "host", "", "Host of the Bitbucket API when using Bitbucket Data Center. For Bitbucket Cloud, this should be left empty.")
4851
createCmd.Flags().StringVarP(&createOptions.User, "user", "u", "", "User's name of the profile")
4952
createCmd.Flags().StringVar(&createOptions.Password, "password", "", "Password of the profile")
5053
createCmd.Flags().StringVar(&createOptions.ClientID, "client-id", "", "Client ID of the profile")
@@ -74,6 +77,11 @@ func init() {
7477
func createProcess(cmd *cobra.Command, args []string) error {
7578
log := logger.Must(logger.FromContext(cmd.Context())).Child(cmd.Parent().Name(), "create")
7679

80+
if len(createOptions.Host) > 0 {
81+
createOptions.APIRoot = &url.URL{Scheme: "https", Host: createOptions.Host, Path: "/rest/1.0"}
82+
} else {
83+
createOptions.APIRoot = &url.URL{Scheme: "https", Host: "api.bitbucket.org", Path: "/2.0"}
84+
}
7785
if len(createOptions.DefaultWorkspace.String()) > 0 {
7886
createOptions.Profile.DefaultWorkspace = createOptions.DefaultWorkspace.String()
7987
}

cmd/profile/profile.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,11 @@ func (profile Profile) GetRow(headers []string) []string {
149149
for _, header := range headers {
150150
switch strings.ToLower(header) {
151151
case "apiroot":
152-
row = append(row, profile.APIRoot.String())
152+
if profile.APIRoot != nil {
153+
row = append(row, profile.APIRoot.String())
154+
} else {
155+
row = append(row, " ")
156+
}
153157
case "name":
154158
row = append(row, profile.Name)
155159
case "description":
@@ -209,6 +213,10 @@ func (profile *Profile) Update(other Profile) error {
209213
if len(other.Name) > 0 {
210214
profile.Name = other.Name
211215
}
216+
if other.APIRoot != nil {
217+
profile.APIRoot = other.APIRoot
218+
}
219+
212220
if len(other.Description) > 0 {
213221
profile.Description = other.Description
214222
}
@@ -264,6 +272,9 @@ func (profile *Profile) Validate() error {
264272
if len(profile.Name) == 0 {
265273
merr.Append(errors.ArgumentMissing.With("name"))
266274
}
275+
if profile.APIRoot == nil {
276+
profile.APIRoot = &url.URL{Scheme: "https", Host: "api.bitbucket.org", Path: "/2.0"}
277+
}
267278
// We must have either an access token, a user, or a clientID
268279
// password and clientSecret are now retrieved from the vault
269280
if len(profile.AccessToken) == 0 && len(profile.ClientID) == 0 && len(profile.User) == 0 {

cmd/profile/profile_client.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,12 @@ func (profile *Profile) send(context context.Context, cmd *cobra.Command, option
409409
return nil, err
410410
}
411411

412-
apiRoot := profile.APIRoot
413-
if apiRoot == nil {
414-
apiRoot = &url.URL{Scheme: "https", Host: "api.bitbucket.org"}
415-
}
412+
// We want a copy og the API Root URL because we will modify it with the path of the request
413+
apiRoot := &url.URL{Scheme: profile.APIRoot.Scheme, Host: profile.APIRoot.Host, Path: profile.APIRoot.Path}
416414

417415
if strings.HasPrefix(uripath, "/") {
418416
components := strings.Split(uripath, "?")
419-
options.URL = apiRoot.JoinPath("2.0", components[0])
417+
options.URL = apiRoot.JoinPath(components[0])
420418
if len(components) > 1 {
421419
options.URL.RawQuery = components[1]
422420
}
@@ -427,7 +425,7 @@ func (profile *Profile) send(context context.Context, cmd *cobra.Command, option
427425
}
428426
log.Infof("Using repository %s", repositoryName)
429427
components := strings.Split(uripath, "?")
430-
options.URL = apiRoot.JoinPath("2.0", "repositories", repositoryName, components[0])
428+
options.URL = apiRoot.JoinPath("repositories", repositoryName, components[0])
431429
if len(components) > 1 {
432430
options.URL.RawQuery = components[1]
433431
}

cmd/profile/profiles.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package profile
33
import (
44
"context"
55
"fmt"
6+
"net/url"
67
"os"
78

89
"bitbucket.org/gildas_cherruel/bb/cmd/common"
@@ -151,6 +152,9 @@ func (profiles *profiles) Load(context context.Context) error {
151152

152153
// Get the secret stuff from the Windows credential manager or linux/macOS keychain if not set
153154
for _, profile := range *profiles {
155+
if profile.APIRoot == nil {
156+
profile.APIRoot = &url.URL{Scheme: "https", Host: "api.bitbucket.org", Path: "/2.0"}
157+
}
154158
if len(profile.ClientID) > 0 {
155159
if len(profile.ClientSecret) == 0 {
156160
if credential, err := profile.GetCredentialFromVault(profile.VaultKey, profile.ClientID); err == nil {

cmd/profile/update.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package profile
22

33
import (
44
"fmt"
5+
"net/url"
56
"os"
67
"path/filepath"
78
"runtime"
@@ -25,6 +26,7 @@ var updateCmd = &cobra.Command{
2526

2627
var updateOptions struct {
2728
Profile
29+
Host string
2830
DefaultWorkspace *flags.EnumFlag
2931
DefaultProject *flags.EnumFlag
3032
OutputFormat *flags.EnumFlag
@@ -44,6 +46,7 @@ func init() {
4446
if runtime.GOOS != "windows" {
4547
updateCmd.Flags().StringVar(&updateOptions.VaultKey, "vault-key", "bitbucket-cli", "Vault key to use for storing credentials. Default is bitbucket-cli. On Windows, the Windows Credential Manager will be used, On Linux and macOS, the system keychain will be used.")
4648
}
49+
updateCmd.Flags().StringVar(&updateOptions.Host, "host", "", "Host of the Bitbucket API when using Bitbucket Data Center. For Bitbucket Cloud, this should be left empty.")
4750
updateCmd.Flags().StringVarP(&updateOptions.User, "user", "u", "", "User's name of the profile")
4851
updateCmd.Flags().StringVar(&updateOptions.Password, "password", "", "Password of the profile")
4952
updateCmd.Flags().StringVar(&updateOptions.ClientID, "client-id", "", "Client ID of the profile")
@@ -70,6 +73,11 @@ func init() {
7073
func updateProcess(cmd *cobra.Command, args []string) error {
7174
log := logger.Must(logger.FromContext(cmd.Context())).Child(cmd.Parent().Name(), "update")
7275

76+
if len(updateOptions.Host) > 0 {
77+
updateOptions.APIRoot = &url.URL{Scheme: "https", Host: updateOptions.Host, Path: "/rest/1.0"}
78+
} else {
79+
updateOptions.APIRoot = &url.URL{Scheme: "https", Host: "api.bitbucket.org", Path: "/2.0"}
80+
}
7381
if len(updateOptions.DefaultWorkspace.String()) > 0 {
7482
updateOptions.Profile.DefaultWorkspace = updateOptions.DefaultWorkspace.String()
7583
}

0 commit comments

Comments
 (0)