fix: bitbucket credential fix backwards-adapted to v0.14.8 (#4139)

diff --git a/plugins/bitbucket/api/blueprint.go b/plugins/bitbucket/api/blueprint.go
index 825670e..41dca8e 100644
--- a/plugins/bitbucket/api/blueprint.go
+++ b/plugins/bitbucket/api/blueprint.go
@@ -37,21 +37,21 @@
 	"github.com/apache/incubator-devlake/utils"
 )
 
-type repoGetter func(connectionId uint64, owner, repo string) (string, string, errors.Error)
+type repoGetter func(connectionId uint64, owner, repo string) (string, *models.BitbucketConnection, errors.Error)
 
 func MakePipelinePlan(subtaskMetas []core.SubTaskMeta, connectionId uint64, scope []*core.BlueprintScopeV100) (core.PipelinePlan, errors.Error) {
 	return makePipelinePlan(subtaskMetas, connectionId, getBitbucketApiRepo, scope)
 }
-func getBitbucketApiRepo(connectionId uint64, owner, repo string) (string, string, errors.Error) {
+func getBitbucketApiRepo(connectionId uint64, owner, repo string) (string, *models.BitbucketConnection, errors.Error) {
 	// here is the tricky part, we have to obtain the repo id beforehand
 	connection := new(models.BitbucketConnection)
 	err := connectionHelper.FirstById(connection, connectionId)
 	if err != nil {
-		return "", "", err
+		return "", nil, err
 	}
 	tokens := strings.Split(connection.GetEncodedToken(), ",")
 	if len(tokens) == 0 {
-		return "", "", errors.Default.New("no token")
+		return "", nil, errors.Default.New("no token")
 	}
 	token := tokens[0]
 	apiClient, err := helper.NewApiClient(
@@ -65,35 +65,35 @@
 		basicRes,
 	)
 	if err != nil {
-		return "", "", err
+		return "", nil, err
 	}
 
 	res, err := apiClient.Get(path.Join("repositories", owner, repo), nil, nil)
 	if err != nil {
-		return "", "", err
+		return "", nil, err
 	}
 	defer res.Body.Close()
 	if res.StatusCode != http.StatusOK {
-		return "", "", errors.Default.New(fmt.Sprintf(
+		return "", nil, errors.Default.New(fmt.Sprintf(
 			"unexpected status code when requesting repo detail %d %s",
 			res.StatusCode, res.Request.URL.String(),
 		))
 	}
 	body, err := errors.Convert01(io.ReadAll(res.Body))
 	if err != nil {
-		return "", "", err
+		return "", nil, err
 	}
 	apiRepo := new(tasks.BitbucketApiRepo)
 	err = errors.Convert(json.Unmarshal(body, apiRepo))
 	if err != nil {
-		return "", "", err
+		return "", nil, err
 	}
 	for _, u := range apiRepo.Links.Clone {
 		if u.Name == "https" {
-			return u.Href, connection.Password, nil
+			return u.Href, connection, nil
 		}
 	}
-	return "", "", errors.Default.New("no clone url")
+	return "", nil, errors.Default.New("no clone url")
 }
 
 func makePipelinePlan(subtaskMetas []core.SubTaskMeta, connectionId uint64, getter repoGetter, scope []*core.BlueprintScopeV100) (core.PipelinePlan, errors.Error) {
@@ -153,7 +153,7 @@
 		})
 		// collect git data by gitextractor if CODE was requested
 		if utils.StringsContains(scopeElem.Entities, core.DOMAIN_TYPE_CODE) {
-			original, password, err1 := getter(connectionId, op.Owner, op.Repo)
+			original, connection, err1 := getter(connectionId, op.Owner, op.Repo)
 			if err1 != nil {
 				return nil, err1
 			}
@@ -161,7 +161,7 @@
 			if err != nil {
 				return nil, err
 			}
-			cloneUrl.User = url.UserPassword(op.Owner, password)
+			cloneUrl.User = url.UserPassword(connection.Username, connection.Password)
 			stage = append(stage, &core.PipelineTask{
 				Plugin: "gitextractor",
 				Options: map[string]interface{}{
diff --git a/plugins/bitbucket/api/blueprint_test.go b/plugins/bitbucket/api/blueprint_test.go
index 14e284a..72d4447 100644
--- a/plugins/bitbucket/api/blueprint_test.go
+++ b/plugins/bitbucket/api/blueprint_test.go
@@ -19,6 +19,8 @@
 
 import (
 	"github.com/apache/incubator-devlake/mocks"
+	"github.com/apache/incubator-devlake/plugins/bitbucket/models"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"testing"
 
 	"github.com/apache/incubator-devlake/errors"
@@ -28,8 +30,13 @@
 
 func TestMakePipelinePlan(t *testing.T) {
 	var mockGetter repoGetter
-	mockGetter = func(connectionId uint64, owner, repo string) (string, string, errors.Error) {
-		return "https://thenicetgp@bitbucket.org/thenicetgp/lake.git", "secret", nil
+	mockGetter = func(connectionId uint64, owner, repo string) (string, *models.BitbucketConnection, errors.Error) {
+		return "https://user:pass@bitbucket.org/thenicetgp/lake.git", &models.BitbucketConnection{
+			BasicAuth: helper.BasicAuth{
+				Username: "user",
+				Password: "pass",
+			},
+		}, nil
 	}
 	scope := &core.BlueprintScopeV100{
 		Entities: []string{core.DOMAIN_TYPE_CODE, core.DOMAIN_TYPE_TICKET, core.DOMAIN_TYPE_CODE_REVIEW, core.DOMAIN_TYPE_CROSS},
@@ -48,7 +55,7 @@
 	for _, stage := range plan {
 		for _, task := range stage {
 			if task.Plugin == "gitextractor" {
-				assert.Equal(t, task.Options["url"], "https://thenicetgp:secret@bitbucket.org/thenicetgp/lake.git")
+				assert.Equal(t, task.Options["url"], "https://user:pass@bitbucket.org/thenicetgp/lake.git")
 				return
 			}
 		}