This is an automated email from the ASF dual-hosted git repository.

warren pushed a commit to branch fix-bitbucket
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/fix-bitbucket by this push:
     new 4384091df feat: add bitbucket pullrequest_commits 
collector&extractor&convertor (#3337)
4384091df is described below

commit 4384091df63a7cb6e6914e5ca350fa672b242502
Author: tsoc <[email protected]>
AuthorDate: Fri Jan 6 13:54:30 2023 +0800

    feat: add bitbucket pullrequest_commits collector&extractor&convertor 
(#3337)
    
    * feat: add bitbucket pullrequest_commits collector&extractor&convertor
    
    * fix: bitbucket commit response do not have committer
    
    Co-authored-by: Klesh Wong <[email protected]>
---
 plugins/bitbucket/impl/impl.go                     |  15 +-
 ...egister.go => 20221008_add_prcommits_tables.go} |  27 ++--
 .../{register.go => archived/pr_commit.go}         |  21 +--
 .../bitbucket/models/migrationscripts/register.go  |   1 +
 .../{migrationscripts/register.go => pr_commit.go} |  21 +--
 plugins/bitbucket/tasks/pr_commit_collector.go     |  69 +++++++++
 plugins/bitbucket/tasks/pr_commit_convertor.go     |  86 +++++++++++
 plugins/bitbucket/tasks/pr_commit_extractor.go     | 159 +++++++++++++++++++++
 8 files changed, 369 insertions(+), 30 deletions(-)

diff --git a/plugins/bitbucket/impl/impl.go b/plugins/bitbucket/impl/impl.go
index 54da3c035..95c41518d 100644
--- a/plugins/bitbucket/impl/impl.go
+++ b/plugins/bitbucket/impl/impl.go
@@ -69,22 +69,33 @@ func (plugin Bitbucket) SubTaskMetas() []core.SubTaskMeta {
        return []core.SubTaskMeta{
                tasks.CollectApiRepoMeta,
                tasks.ExtractApiRepoMeta,
+
                tasks.CollectApiPullRequestsMeta,
                tasks.ExtractApiPullRequestsMeta,
-               tasks.CollectApiIssuesMeta,
-               tasks.ExtractApiIssuesMeta,
+
                tasks.CollectApiPrCommentsMeta,
                tasks.ExtractApiPrCommentsMeta,
+
+               tasks.CollectApiPrCommitsMeta,
+               tasks.ExtractApiPrCommitsMeta,
+
+               tasks.CollectApiIssuesMeta,
+               tasks.ExtractApiIssuesMeta,
+
                tasks.CollectApiIssueCommentsMeta,
                tasks.ExtractApiIssueCommentsMeta,
+
                tasks.CollectApiPipelinesMeta,
                tasks.ExtractApiPipelinesMeta,
+
                tasks.CollectApiDeploymentsMeta,
                tasks.ExtractApiDeploymentsMeta,
+
                tasks.ConvertRepoMeta,
                tasks.ConvertAccountsMeta,
                tasks.ConvertPullRequestsMeta,
                tasks.ConvertPrCommentsMeta,
+               tasks.ConvertPrCommitsMeta,
                tasks.ConvertIssuesMeta,
                tasks.ConvertIssueCommentsMeta,
                tasks.ConvertPipelineMeta,
diff --git a/plugins/bitbucket/models/migrationscripts/register.go 
b/plugins/bitbucket/models/migrationscripts/20221008_add_prcommits_tables.go
similarity index 57%
copy from plugins/bitbucket/models/migrationscripts/register.go
copy to 
plugins/bitbucket/models/migrationscripts/20221008_add_prcommits_tables.go
index d6d7fc8eb..d3a0f0888 100644
--- a/plugins/bitbucket/models/migrationscripts/register.go
+++ b/plugins/bitbucket/models/migrationscripts/20221008_add_prcommits_tables.go
@@ -18,15 +18,26 @@ limitations under the License.
 package migrationscripts
 
 import (
-       "github.com/apache/incubator-devlake/plugins/core"
+       "context"
+       "github.com/apache/incubator-devlake/errors"
+       
"github.com/apache/incubator-devlake/plugins/bitbucket/models/migrationscripts/archived"
+       "gorm.io/gorm"
 )
 
-// All return all the migration scripts
-func All() []core.MigrationScript {
-       return []core.MigrationScript{
-               new(addInitTables20220803),
-               new(addPipeline20220914),
-               new(addDeployment20221013),
-               new(addRepoIdAndCommitShaField20221014),
+type addPrCommits20221008 struct{}
+
+func (*addPrCommits20221008) Up(ctx context.Context, db *gorm.DB) errors.Error 
{
+       err := db.Migrator().AutoMigrate(&archived.BitbucketPrCommit{})
+       if err != nil {
+               return errors.Convert(err)
        }
+       return nil
+}
+
+func (*addPrCommits20221008) Version() uint64 {
+       return 20221008182354
+}
+
+func (*addPrCommits20221008) Name() string {
+       return "bitbucket add _tool_bitbucket_pull_requests_commits table"
 }
diff --git a/plugins/bitbucket/models/migrationscripts/register.go 
b/plugins/bitbucket/models/migrationscripts/archived/pr_commit.go
similarity index 66%
copy from plugins/bitbucket/models/migrationscripts/register.go
copy to plugins/bitbucket/models/migrationscripts/archived/pr_commit.go
index d6d7fc8eb..0721a9606 100644
--- a/plugins/bitbucket/models/migrationscripts/register.go
+++ b/plugins/bitbucket/models/migrationscripts/archived/pr_commit.go
@@ -15,18 +15,19 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package migrationscripts
+package archived
 
 import (
-       "github.com/apache/incubator-devlake/plugins/core"
+       "github.com/apache/incubator-devlake/models/migrationscripts/archived"
 )
 
-// All return all the migration scripts
-func All() []core.MigrationScript {
-       return []core.MigrationScript{
-               new(addInitTables20220803),
-               new(addPipeline20220914),
-               new(addDeployment20221013),
-               new(addRepoIdAndCommitShaField20221014),
-       }
+type BitbucketPrCommit struct {
+       ConnectionId  uint64 `gorm:"primaryKey"`
+       CommitSha     string `gorm:"primaryKey;type:varchar(40)"`
+       PullRequestId int    `gorm:"primaryKey;autoIncrement:false"`
+       archived.NoPKModel
+}
+
+func (BitbucketPrCommit) TableName() string {
+       return "_tool_bitbucket_pull_request_commits"
 }
diff --git a/plugins/bitbucket/models/migrationscripts/register.go 
b/plugins/bitbucket/models/migrationscripts/register.go
index d6d7fc8eb..d5f5374b1 100644
--- a/plugins/bitbucket/models/migrationscripts/register.go
+++ b/plugins/bitbucket/models/migrationscripts/register.go
@@ -26,6 +26,7 @@ func All() []core.MigrationScript {
        return []core.MigrationScript{
                new(addInitTables20220803),
                new(addPipeline20220914),
+               new(addPrCommits20221008),
                new(addDeployment20221013),
                new(addRepoIdAndCommitShaField20221014),
        }
diff --git a/plugins/bitbucket/models/migrationscripts/register.go 
b/plugins/bitbucket/models/pr_commit.go
similarity index 67%
copy from plugins/bitbucket/models/migrationscripts/register.go
copy to plugins/bitbucket/models/pr_commit.go
index d6d7fc8eb..262093242 100644
--- a/plugins/bitbucket/models/migrationscripts/register.go
+++ b/plugins/bitbucket/models/pr_commit.go
@@ -15,18 +15,19 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 */
 
-package migrationscripts
+package models
 
 import (
-       "github.com/apache/incubator-devlake/plugins/core"
+       "github.com/apache/incubator-devlake/models/common"
 )
 
-// All return all the migration scripts
-func All() []core.MigrationScript {
-       return []core.MigrationScript{
-               new(addInitTables20220803),
-               new(addPipeline20220914),
-               new(addDeployment20221013),
-               new(addRepoIdAndCommitShaField20221014),
-       }
+type BitbucketPrCommit struct {
+       ConnectionId  uint64 `gorm:"primaryKey"`
+       CommitSha     string `gorm:"primaryKey;type:varchar(40)"`
+       PullRequestId int    `gorm:"primaryKey;autoIncrement:false"`
+       common.NoPKModel
+}
+
+func (BitbucketPrCommit) TableName() string {
+       return "_tool_bitbucket_pull_request_commits"
 }
diff --git a/plugins/bitbucket/tasks/pr_commit_collector.go 
b/plugins/bitbucket/tasks/pr_commit_collector.go
new file mode 100644
index 000000000..f3464c8e3
--- /dev/null
+++ b/plugins/bitbucket/tasks/pr_commit_collector.go
@@ -0,0 +1,69 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tasks
+
+import (
+       "fmt"
+       "net/url"
+
+       "github.com/apache/incubator-devlake/errors"
+       "github.com/apache/incubator-devlake/plugins/core"
+       "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+const RAW_PULL_REQUEST_COMMITS_TABLE = "bitbucket_api_pull_request_commits"
+
+var CollectApiPrCommitsMeta = core.SubTaskMeta{
+       Name:             "collectApiPullRequestCommits",
+       EntryPoint:       CollectApiPullRequestCommits,
+       EnabledByDefault: true,
+       Description:      "Collect PullRequestCommits data from Bitbucket api",
+       DomainTypes:      []string{core.DOMAIN_TYPE_CODE_REVIEW},
+}
+
+func CollectApiPullRequestCommits(taskCtx core.SubTaskContext) errors.Error {
+       rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, 
RAW_PULL_REQUEST_COMMITS_TABLE)
+
+       iterator, err := GetPullRequestsIterator(taskCtx)
+       if err != nil {
+               return err
+       }
+       defer iterator.Close()
+
+       collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
+               RawDataSubTaskArgs: *rawDataSubTaskArgs,
+               ApiClient:          data.ApiClient,
+               PageSize:           100,
+               Incremental:        false,
+               Input:              iterator,
+               UrlTemplate:        "repositories/{{ .Params.Owner }}/{{ 
.Params.Repo }}/pullrequests/{{ .Input.BitbucketId }}/commits",
+               Query: func(reqData *helper.RequestData) (url.Values, 
errors.Error) {
+                       query := url.Values{}
+                       query.Set("state", "all")
+                       query.Set("pagelen", fmt.Sprintf("%v", 
reqData.Pager.Size))
+
+                       return query, nil
+               },
+               ResponseParser: GetRawMessageFromResponse,
+       })
+
+       if err != nil {
+               return err
+       }
+       return collector.Execute()
+}
diff --git a/plugins/bitbucket/tasks/pr_commit_convertor.go 
b/plugins/bitbucket/tasks/pr_commit_convertor.go
new file mode 100644
index 000000000..5e8f58951
--- /dev/null
+++ b/plugins/bitbucket/tasks/pr_commit_convertor.go
@@ -0,0 +1,86 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tasks
+
+import (
+       "reflect"
+
+       "github.com/apache/incubator-devlake/errors"
+       "github.com/apache/incubator-devlake/models/domainlayer/code"
+       "github.com/apache/incubator-devlake/models/domainlayer/didgen"
+       bitbucketModels 
"github.com/apache/incubator-devlake/plugins/bitbucket/models"
+       "github.com/apache/incubator-devlake/plugins/core"
+       "github.com/apache/incubator-devlake/plugins/core/dal"
+       "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+var ConvertPrCommitsMeta = core.SubTaskMeta{
+       Name:             "convertPullRequestCommits",
+       EntryPoint:       ConvertPullRequestCommits,
+       EnabledByDefault: true,
+       Description:      "Convert tool layer table 
bitbucket_pull_request_commits into  domain layer table pull_request_commits",
+       DomainTypes:      []string{core.DOMAIN_TYPE_CODE_REVIEW},
+}
+
+func ConvertPullRequestCommits(taskCtx core.SubTaskContext) (err errors.Error) 
{
+       db := taskCtx.GetDal()
+       data := taskCtx.GetData().(*BitbucketTaskData)
+       repoId := data.Repo.BitbucketId
+
+       pullIdGen := 
didgen.NewDomainIdGenerator(&bitbucketModels.BitbucketPullRequest{})
+
+       cursor, err := db.Cursor(
+               dal.From(&bitbucketModels.BitbucketPrCommit{}),
+               dal.Join(`left join _tool_bitbucket_pull_requests on 
_tool_bitbucket_pull_requests.bitbucket_id = 
_tool_bitbucket_pull_request_commits.pull_request_id`),
+               dal.Where("_tool_bitbucket_pull_requests.repo_id = ? and 
_tool_bitbucket_pull_requests.connection_id = ?", repoId, 
data.Options.ConnectionId),
+               dal.Orderby("pull_request_id ASC"),
+       )
+       if err != nil {
+               return err
+       }
+       defer cursor.Close()
+
+       converter, err := helper.NewDataConverter(helper.DataConverterArgs{
+               InputRowType: 
reflect.TypeOf(bitbucketModels.BitbucketPrCommit{}),
+               Input:        cursor,
+               RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+                       Ctx: taskCtx,
+                       Params: BitbucketApiParams{
+                               ConnectionId: data.Options.ConnectionId,
+                               Owner:        data.Options.Owner,
+                               Repo:         data.Options.Repo,
+                       },
+                       Table: RAW_PULL_REQUEST_COMMITS_TABLE,
+               },
+               Convert: func(inputRow interface{}) ([]interface{}, 
errors.Error) {
+                       bitbucketPullRequestCommit := 
inputRow.(*bitbucketModels.BitbucketPrCommit)
+                       domainPrCommit := &code.PullRequestCommit{
+                               CommitSha:     
bitbucketPullRequestCommit.CommitSha,
+                               PullRequestId: 
pullIdGen.Generate(data.Options.ConnectionId, 
bitbucketPullRequestCommit.PullRequestId),
+                       }
+                       return []interface{}{
+                               domainPrCommit,
+                       }, nil
+               },
+       })
+       if err != nil {
+               return err
+       }
+
+       return converter.Execute()
+}
diff --git a/plugins/bitbucket/tasks/pr_commit_extractor.go 
b/plugins/bitbucket/tasks/pr_commit_extractor.go
new file mode 100644
index 000000000..38552d996
--- /dev/null
+++ b/plugins/bitbucket/tasks/pr_commit_extractor.go
@@ -0,0 +1,159 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tasks
+
+import (
+       "encoding/json"
+       "strings"
+       "time"
+
+       "github.com/apache/incubator-devlake/errors"
+       "github.com/apache/incubator-devlake/plugins/bitbucket/models"
+       "github.com/apache/incubator-devlake/plugins/core"
+       "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+var ExtractApiPrCommitsMeta = core.SubTaskMeta{
+       Name:             "extractApiPullRequestCommits",
+       EntryPoint:       ExtractApiPullRequestCommits,
+       EnabledByDefault: true,
+       Description:      "Extract raw PullRequestCommits data into tool layer 
table bitbucket_commits",
+       DomainTypes:      []string{core.DOMAIN_TYPE_CODE_REVIEW},
+}
+
+type ApiPrCommitsResponse struct {
+       Type   string    `json:"type"`
+       Hash   string    `json:"hash"`
+       Date   time.Time `json:"date"`
+       Author struct {
+               Type string                   `json:"type"`
+               Raw  string                   `json:"raw"`
+               User BitbucketAccountResponse `json:"user"`
+       } `json:"author"`
+       Message string `json:"message"`
+       Summary struct {
+               Type   string `json:"type"`
+               Raw    string `json:"raw"`
+               Markup string `json:"markup"`
+               HTML   string `json:"html"`
+       } `json:"summary"`
+       Links struct {
+               Self struct {
+                       Href string `json:"href"`
+               } `json:"self"`
+               HTML struct {
+                       Href string `json:"href"`
+               } `json:"html"`
+       } `json:"links"`
+       Parents []struct {
+               Type  string `json:"type"`
+               Hash  string `json:"hash"`
+               Links struct {
+                       Self struct {
+                               Href string `json:"href"`
+                       } `json:"self"`
+                       HTML struct {
+                               Href string `json:"href"`
+                       } `json:"html"`
+               } `json:"links"`
+       } `json:"parents"`
+       Repository BitbucketApiRepo `json:"repository"`
+}
+
+func ExtractApiPullRequestCommits(taskCtx core.SubTaskContext) errors.Error {
+       data := taskCtx.GetData().(*BitbucketTaskData)
+       repoId := data.Repo.BitbucketId
+       extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
+               RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+                       Ctx: taskCtx,
+                       /*
+                               This struct will be JSONEncoded and stored into 
database along with raw data itself, to identity minimal
+                               set of data to be process, for example, we 
process JiraIssues by Board
+                       */
+                       Params: BitbucketApiParams{
+                               ConnectionId: data.Options.ConnectionId,
+                               Owner:        data.Options.Owner,
+                               Repo:         data.Options.Repo,
+                       },
+                       /*
+                               Table store raw data
+                       */
+                       Table: RAW_PULL_REQUEST_COMMITS_TABLE,
+               },
+               Extract: func(row *helper.RawData) ([]interface{}, 
errors.Error) {
+                       apiPullRequestCommit := &ApiPrCommitsResponse{}
+                       if strings.HasPrefix(string(row.Data), "Not Found") {
+                               return nil, nil
+                       }
+                       err := errors.Convert(json.Unmarshal(row.Data, 
apiPullRequestCommit))
+                       if err != nil {
+                               return nil, err
+                       }
+                       pull := &BitbucketInput{}
+                       err = errors.Convert(json.Unmarshal(row.Input, pull))
+                       if err != nil {
+                               return nil, err
+                       }
+                       // need to extract 2 kinds of entities here
+                       results := make([]interface{}, 0, 3)
+                       bitbucketRepoCommit := &models.BitbucketRepoCommit{
+                               ConnectionId: data.Options.ConnectionId,
+                               RepoId:       repoId,
+                               CommitSha:    apiPullRequestCommit.Hash,
+                       }
+                       results = append(results, bitbucketRepoCommit)
+
+                       bitbucketCommit, err := 
convertPullRequestCommit(apiPullRequestCommit, data.Options.ConnectionId)
+                       if err != nil {
+                               return nil, err
+                       }
+                       results = append(results, bitbucketCommit)
+
+                       bitbucketPullRequestCommit := &models.BitbucketPrCommit{
+                               ConnectionId:  data.Options.ConnectionId,
+                               CommitSha:     apiPullRequestCommit.Hash,
+                               PullRequestId: pull.BitbucketId,
+                       }
+                       if err != nil {
+                               return nil, err
+                       }
+                       results = append(results, bitbucketPullRequestCommit)
+                       return results, nil
+               },
+       })
+
+       if err != nil {
+               return err
+       }
+
+       return extractor.Execute()
+}
+
+func convertPullRequestCommit(prCommit *ApiPrCommitsResponse, connId uint64) 
(*models.BitbucketCommit, errors.Error) {
+       bitbucketCommit := &models.BitbucketCommit{
+               Sha:           prCommit.Hash,
+               Message:       prCommit.Message,
+               AuthorId:      prCommit.Author.User.AccountId,
+               AuthorName:    prCommit.Author.User.UserName,
+               AuthorEmail:   prCommit.Author.Raw,
+               AuthoredDate:  prCommit.Date,
+               CommittedDate: prCommit.Date,
+               Url:           prCommit.Links.Self.Href,
+       }
+       return bitbucketCommit, nil
+}

Reply via email to