diff --git a/CHANGELOG.md b/CHANGELOG.md index 28520d93..8f447163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) ## [1.7.6] - unreleased ### Added - goreleaser +- GHORG_BITBUCKET_OAUTH_TOKEN to support oauth tokens for bitbucket ### Changed ### Deprecated ### Removed diff --git a/README.md b/README.md index c9cac578..8385cfe4 100644 --- a/README.md +++ b/README.md @@ -155,9 +155,17 @@ $ ghorg clone fdroid --scm=gitlab --token=XXXX --preserve-dir ### bitbucket setup -1. To configure with bitbucket you will need to create a new [app password](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html) and update your `$HOME/.config/ghorg/conf.yaml` [here](https://github.com/gabrie30/ghorg/blob/master/sample-conf.yaml#L37-L47) or use the (--token, -t) and (--bitbucket-username) flags. +#### app passwords + +1. To configure with bitbucket you will need to create a new [app password](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html) and update your `$HOME/.config/ghorg/conf.yaml` or use the (--token, -t) and (--bitbucket-username) flags. 1. Update [SCM type](https://github.com/gabrie30/ghorg/blob/master/sample-conf.yaml#L54-L57) to `bitbucket` in your `ghorg/conf.yaml` or via cli flags +#### PAT/OAuth token + +1. Create a [PAT](https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html) +1. Set the token with `GHORG_BITBUCKET_OAUTH_TOKEN` in your `$HOME/.config/ghorg/conf.yaml` or using the `--token` flag. Make sure you do not have `--bitbucket-username` set. +1. Update SCM TYPE to `bitbucket` in your `ghorg/conf.yaml` or via cli flags + ### osx default github/gitlab token used > NOTE: cloning via https rather than ssh is the ghorg default, this is because a token must be present to retrieve the list of repos. However, if you run into trouble cloning via https and generally clone via ssh, try switching `--protocol ssh` diff --git a/cmd/clone.go b/cmd/clone.go index b9b0bcbd..79cdef98 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -140,7 +140,12 @@ func cloneFunc(cmd *cobra.Command, argz []string) { } else if os.Getenv("GHORG_SCM_TYPE") == "gitlab" { os.Setenv("GHORG_GITLAB_TOKEN", cmd.Flag("token").Value.String()) } else if os.Getenv("GHORG_SCM_TYPE") == "bitbucket" { - os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", cmd.Flag("token").Value.String()) + if cmd.Flags().Changed("bitbucket-username") { + os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", cmd.Flag("token").Value.String()) + } else { + os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", cmd.Flag("token").Value.String()) + } + } else if os.Getenv("GHORG_SCM_TYPE") == "gitea" { os.Setenv("GHORG_GITEA_TOKEN", cmd.Flag("token").Value.String()) } diff --git a/cmd/root.go b/cmd/root.go index 0b09812f..00a47681 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -169,6 +169,7 @@ func InitConfig() { getOrSetDefaults("GHORG_GITLAB_TOKEN") getOrSetDefaults("GHORG_BITBUCKET_USERNAME") getOrSetDefaults("GHORG_BITBUCKET_APP_PASSWORD") + getOrSetDefaults("GHORG_BITBUCKET_OAUTH_TOKEN") getOrSetDefaults("GHORG_SCM_BASE_URL") getOrSetDefaults("GHORG_PRESERVE_DIRECTORY_STRUCTURE") getOrSetDefaults("GHORG_OUTPUT_DIR") @@ -196,7 +197,7 @@ func init() { cloneCmd.Flags().StringVar(&protocol, "protocol", "", "GHORG_CLONE_PROTOCOL - protocol to clone with, ssh or https, (default https)") cloneCmd.Flags().StringVarP(&path, "path", "p", "", "GHORG_ABSOLUTE_PATH_TO_CLONE_TO - absolute path the ghorg_* directory will be created. Must end with / (default $HOME/Desktop/ghorg)") cloneCmd.Flags().StringVarP(&branch, "branch", "b", "", "GHORG_BRANCH - branch left checked out for each repo cloned (default master)") - cloneCmd.Flags().StringVarP(&token, "token", "t", "", "GHORG_GITHUB_TOKEN/GHORG_GITLAB_TOKEN/GHORG_GITEA_TOKEN/GHORG_BITBUCKET_APP_PASSWORD - scm token to clone with") + cloneCmd.Flags().StringVarP(&token, "token", "t", "", "GHORG_GITHUB_TOKEN/GHORG_GITLAB_TOKEN/GHORG_GITEA_TOKEN/GHORG_BITBUCKET_APP_PASSWORD/GHORG_BITBUCKET_OAUTH_TOKEN - scm token to clone with") cloneCmd.Flags().StringVarP(&bitbucketUsername, "bitbucket-username", "", "", "GHORG_BITBUCKET_USERNAME - bitbucket only: username associated with the app password") cloneCmd.Flags().StringVarP(&scmType, "scm", "s", "", "GHORG_SCM_TYPE - type of scm used, github, gitlab, gitea or bitbucket (default github)") cloneCmd.Flags().StringVarP(&cloneType, "clone-type", "c", "", "GHORG_CLONE_TYPE - clone target type, user or org (default org)") diff --git a/configs/configs.go b/configs/configs.go index 67425bdf..cd3c96ca 100644 --- a/configs/configs.go +++ b/configs/configs.go @@ -193,7 +193,7 @@ func getOrSetGitLabToken() { func getOrSetBitBucketToken() { var token string - if isZero(os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")) || len(os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")) != 20 { + if isZero(os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")) && isZero(os.Getenv("GHORG_BITBUCKET_OAUTH_TOKEN")) { if runtime.GOOS == "windows" { return } @@ -205,7 +205,11 @@ func getOrSetBitBucketToken() { token = strings.TrimSuffix(string(out), "\n") - os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", token) + if !isZero(os.Getenv("GHORG_BITBUCKET_USERNAME")) { + os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", token) + } else { + os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", token) + } } } @@ -231,10 +235,18 @@ func VerifyTokenSet() error { if scmProvider == "bitbucket" { tokenLength = 20 - token = os.Getenv("GHORG_BITBUCKET_APP_PASSWORD") - if os.Getenv("GHORG_BITBUCKET_USERNAME") == "" { + if os.Getenv("GHORG_BITBUCKET_USERNAME") == "" && len(os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")) == 20 { return ErrNoBitbucketUsername } + + if isZero(os.Getenv("GHORG_BITBUCKET_USERNAME")) { + // todo not sure how long this is so, so just make it pass for now + tokenLength = 0 + token = "" + } else { + token = os.Getenv("GHORG_BITBUCKET_APP_PASSWORD") + } + } if len(token) != tokenLength { diff --git a/configs/configs_test.go b/configs/configs_test.go index 45959c61..c7ac5a29 100644 --- a/configs/configs_test.go +++ b/configs/configs_test.go @@ -34,6 +34,7 @@ func TestVerifyTokenSet(t *testing.T) { t.Run("When cloning bitbucket with no username", func(tt *testing.T) { os.Setenv("GHORG_SCM_TYPE", "bitbucket") os.Setenv("GHORG_BITBUCKET_USERNAME", "") + os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "12345678912345678901") err := configs.VerifyTokenSet() if err != configs.ErrNoBitbucketUsername { tt.Errorf("Expected ErrNoBitbucketUsername, got: %v", err) diff --git a/sample-conf.yaml b/sample-conf.yaml index 42bca219..4c9c6678 100644 --- a/sample-conf.yaml +++ b/sample-conf.yaml @@ -40,11 +40,17 @@ GHORG_GITEA_TOKEN: # |B|I|T|B|U|C|K|E|T| |S|P|E|C|I|F|I|C| # +-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ -# Add your Bitbucket app password +# When using this OAuth/PAT token, do not set the bitbucket username flag. Do not set both this value and the GHORG_BITBUCKET_APP_PASSWORD +# https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html +# flag (--token, -t) eg: --token=bGVhdmUgYSBjb21tZW50IG9uIGlzc3VlIDY2 +GHORG_BITBUCKET_OAUTH_TOKEN: + +# Add your Bitbucket app password. Do not set both this value and the GHORG_BITBUCKET_OAUTH_TOKEN # https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html # flag (--token, -t) eg: --token=bGVhdmUgYSBjb21tZW50IG9uIGlzc3VlIDY2 GHORG_BITBUCKET_APP_PASSWORD: +# Used with GHORG_BITBUCKET_APP_PASSWORD. Should not be set when using GHORG_BITBUCKET_OAUTH_TOKEN # flag (--bitbucket-username) eg: --bitbucket-username=user123 GHORG_BITBUCKET_USERNAME: diff --git a/scm/bitbucket.go b/scm/bitbucket.go index 04c30b14..cf1388df 100644 --- a/scm/bitbucket.go +++ b/scm/bitbucket.go @@ -48,7 +48,14 @@ func (c Bitbucket) GetUserRepos(targetUser string) ([]Repo, error) { func (_ Bitbucket) NewClient() (Client, error) { user := os.Getenv("GHORG_BITBUCKET_USERNAME") password := os.Getenv("GHORG_BITBUCKET_APP_PASSWORD") - c := bitbucket.NewBasicAuth(user, password) + oAuth := os.Getenv("GHORG_BITBUCKET_OAUTH") + var c *bitbucket.Client + + if oAuth != "" { + c = bitbucket.NewOAuthbearerToken(oAuth) + } else { + c = bitbucket.NewBasicAuth(user, password) + } return Bitbucket{c}, nil }