This is an automated email from the ASF dual-hosted git repository. lynwee pushed a commit to branch dev-1 in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 203ebd600bcc1f0f0ad8305d578a75999fd31a4d Author: d4x1 <[email protected]> AuthorDate: Wed Sep 11 18:32:36 2024 +0800 feat(plugins): restranformate without api client --- backend/plugins/ae/impl/impl.go | 11 ++- backend/plugins/azuredevops_go/impl/impl.go | 11 ++- backend/plugins/bamboo/impl/impl.go | 13 +++- .../plugins/bamboo/tasks/plan_commit_convertor.go | 2 +- backend/plugins/bamboo/tasks/task_data.go | 1 + backend/plugins/bitbucket/api/blueprint_v200.go | 8 ++- backend/plugins/bitbucket/impl/impl.go | 48 ++++++++----- .../plugins/bitbucket_server/api/blueprint_v200.go | 12 ++-- backend/plugins/bitbucket_server/impl/impl.go | 48 ++++++++----- backend/plugins/feishu/impl/impl.go | 11 ++- backend/plugins/gitee/impl/impl.go | 11 ++- backend/plugins/icla/impl/impl.go | 11 ++- backend/plugins/jenkins/api/blueprint_v200.go | 12 ++-- backend/plugins/jenkins/impl/impl.go | 39 ++++++----- backend/plugins/jira/api/blueprint_v200.go | 12 ++-- backend/plugins/jira/impl/impl.go | 59 ++++++++++------ .../20240910_add_table_tool_jira_server_info.go} | 32 ++++----- .../migrationscripts/archived/jira_server_info.go} | 34 ++++------ .../jira/models/migrationscripts/register.go | 1 + backend/plugins/jira/models/response_type.go | 7 +- backend/plugins/jira/tasks/account_collector.go | 7 +- backend/plugins/jira/tasks/epic_collector.go | 14 ++-- .../jira/tasks/issue_changelog_collector.go | 10 ++- .../jira/tasks/issue_changelog_extractor.go | 8 ++- backend/plugins/jira/tasks/issue_collector.go | 7 +- .../plugins/jira/tasks/issue_comment_collector.go | 7 +- .../plugins/jira/tasks/issue_comment_extractor.go | 7 +- backend/plugins/jira/tasks/issue_type_collector.go | 7 +- backend/plugins/jira/tasks/shared.go | 36 ++++++++++ backend/plugins/jira/tasks/sprint_extractor.go | 9 +-- backend/plugins/jira/tasks/task_data.go | 2 +- backend/plugins/opsgenie/impl/impl.go | 21 +++--- backend/plugins/pagerduty/impl/impl.go | 21 +++--- backend/plugins/slack/impl/impl.go | 11 ++- backend/plugins/sonarqube/api/blueprint_v200.go | 12 ++-- backend/plugins/sonarqube/impl/impl.go | 40 ++++++----- backend/plugins/tapd/impl/impl.go | 13 ++-- backend/plugins/teambition/impl/impl.go | 11 ++- backend/plugins/trello/impl/impl.go | 11 ++- backend/plugins/zentao/impl/impl.go | 79 ++++++++++++++++------ .../plugins/zentao/tasks/execution_convertor.go | 9 +-- backend/plugins/zentao/tasks/project_convertor.go | 8 +-- backend/plugins/zentao/tasks/shared.go | 16 ----- backend/plugins/zentao/tasks/task_data.go | 1 + 44 files changed, 477 insertions(+), 273 deletions(-) diff --git a/backend/plugins/ae/impl/impl.go b/backend/plugins/ae/impl/impl.go index 325146bef..389857e1f 100644 --- a/backend/plugins/ae/impl/impl.go +++ b/backend/plugins/ae/impl/impl.go @@ -107,9 +107,14 @@ func (p AE) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]inter if err != nil { return nil, errors.Default.Wrap(err, "error getting connection for AE plugin") } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, err + } + apiClient = newApiClient } return &tasks.AeTaskData{ Options: &op, diff --git a/backend/plugins/azuredevops_go/impl/impl.go b/backend/plugins/azuredevops_go/impl/impl.go index f82db88e1..c567e49f5 100644 --- a/backend/plugins/azuredevops_go/impl/impl.go +++ b/backend/plugins/azuredevops_go/impl/impl.go @@ -127,9 +127,14 @@ func (p Azuredevops) PrepareTaskData(taskCtx plugin.TaskContext, options map[str return nil, errors.Default.Wrap(err, "failed to retrieve an Azure DevOps connection from the database using the provided connection ID") } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "failed to retrieve an Azure DevOps connection from the database using the provided connection ID") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "failed to retrieve an Azure DevOps connection from the database using the provided connection ID") + } + apiClient = newApiClient } if op.RepositoryId != "" { diff --git a/backend/plugins/bamboo/impl/impl.go b/backend/plugins/bamboo/impl/impl.go index bc722c1b9..2aae7ad5e 100644 --- a/backend/plugins/bamboo/impl/impl.go +++ b/backend/plugins/bamboo/impl/impl.go @@ -140,10 +140,16 @@ func (p Bamboo) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]i if err != nil { return nil, errors.Default.Wrap(err, "unable to get Bamboo connection by the given connection ID") } + endPoint := connection.GetEndpoint() - apiClient, err := tasks.NewBambooApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "unable to get Bamboo API client instance") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.NewBambooApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "unable to get Bamboo API client instance") + } + apiClient = newApiClient } if op.PlanKey != "" { var scope *models.BambooPlan @@ -189,6 +195,7 @@ func (p Bamboo) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]i return &tasks.BambooOptions{ Options: op, ApiClient: apiClient, + EndPoint: endPoint, RegexEnricher: regexEnricher, }, nil } diff --git a/backend/plugins/bamboo/tasks/plan_commit_convertor.go b/backend/plugins/bamboo/tasks/plan_commit_convertor.go index 13104d89c..5c4c0a4ba 100644 --- a/backend/plugins/bamboo/tasks/plan_commit_convertor.go +++ b/backend/plugins/bamboo/tasks/plan_commit_convertor.go @@ -66,7 +66,7 @@ func ConvertPlanVcs(taskCtx plugin.SubTaskContext) errors.Error { Url: line.Url, } domainPlanVcs.RepoId = repoMap[line.RepositoryId] - fakeRepoUrl, err := generateFakeRepoUrl(data.ApiClient.GetEndpoint(), line.RepositoryId) + fakeRepoUrl, err := generateFakeRepoUrl(data.EndPoint, line.RepositoryId) if err != nil { logger.Warn(err, "generate fake repo url, endpoint: %s, repo id: %d", data.ApiClient.GetEndpoint(), line.RepositoryId) } else { diff --git a/backend/plugins/bamboo/tasks/task_data.go b/backend/plugins/bamboo/tasks/task_data.go index c5427ac1a..dc240c55f 100644 --- a/backend/plugins/bamboo/tasks/task_data.go +++ b/backend/plugins/bamboo/tasks/task_data.go @@ -26,6 +26,7 @@ import ( type BambooOptions struct { Options *models.BambooOptions ApiClient *helper.ApiAsyncClient + EndPoint string RegexEnricher *helper.RegexEnricher } diff --git a/backend/plugins/bitbucket/api/blueprint_v200.go b/backend/plugins/bitbucket/api/blueprint_v200.go index e9ce9f333..3438a039b 100644 --- a/backend/plugins/bitbucket/api/blueprint_v200.go +++ b/backend/plugins/bitbucket/api/blueprint_v200.go @@ -54,9 +54,11 @@ func MakeDataSourcePipelinePlanV200( // needed for the connection to populate its access tokens // if AppKey authentication method is selected - _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) - if err != nil { - return nil, nil, err + if !skipCollectors { + _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) + if err != nil { + return nil, nil, err + } } plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, scopeDetails, connection) diff --git a/backend/plugins/bitbucket/impl/impl.go b/backend/plugins/bitbucket/impl/impl.go index 8d5123620..9a23ab1b3 100644 --- a/backend/plugins/bitbucket/impl/impl.go +++ b/backend/plugins/bitbucket/impl/impl.go @@ -154,13 +154,25 @@ func (p Bitbucket) PrepareTaskData(taskCtx plugin.TaskContext, options map[strin return nil, errors.Default.Wrap(err, "unable to get bitbucket connection by the given connection ID") } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "unable to get bitbucket API client instance") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "unable to get bitbucket API client instance") + } + apiClient = newApiClient } - err = EnrichOptions(taskCtx, op, apiClient.ApiClient) - if err != nil { - return nil, err + if apiClient == nil { + err = EnrichOptions(taskCtx, op, nil) + if err != nil { + return nil, err + } + } else { + err = EnrichOptions(taskCtx, op, apiClient.ApiClient) + if err != nil { + return nil, err + } } regexEnricher := helper.NewRegexEnricher() @@ -276,17 +288,19 @@ func EnrichOptions(taskCtx plugin.TaskContext, } } else { if taskCtx.GetDal().IsErrorNotFound(err) && op.FullName != "" { - var repo *models.BitbucketApiRepo - repo, err = tasks.GetApiRepo(op, apiClient) - if err != nil { - return err - } - logger.Debug(fmt.Sprintf("Current repo: %s", repo.FullName)) - scope := repo.ConvertApiScope() - scope.ConnectionId = op.ConnectionId - err = taskCtx.GetDal().CreateIfNotExist(scope) - if err != nil { - return err + if apiClient != nil { + var repo *models.BitbucketApiRepo + repo, err = tasks.GetApiRepo(op, apiClient) + if err != nil { + return err + } + logger.Debug(fmt.Sprintf("Current repo: %s", repo.FullName)) + scope := repo.ConvertApiScope() + scope.ConnectionId = op.ConnectionId + err = taskCtx.GetDal().CreateIfNotExist(scope) + if err != nil { + return err + } } } else { return errors.Default.Wrap(err, fmt.Sprintf("fail to find repo %s", op.FullName)) diff --git a/backend/plugins/bitbucket_server/api/blueprint_v200.go b/backend/plugins/bitbucket_server/api/blueprint_v200.go index 21ce03ff6..7c2f6dc39 100644 --- a/backend/plugins/bitbucket_server/api/blueprint_v200.go +++ b/backend/plugins/bitbucket_server/api/blueprint_v200.go @@ -52,11 +52,13 @@ func MakeDataSourcePipelinePlanV200( return nil, nil, err } - // needed for the connection to populate its access tokens - // if AppKey authentication method is selected - _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) - if err != nil { - return nil, nil, err + if !skipCollectors { + // needed for the connection to populate its access tokens + // if AppKey authentication method is selected + _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) + if err != nil { + return nil, nil, err + } } plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, scopeDetails, connection) diff --git a/backend/plugins/bitbucket_server/impl/impl.go b/backend/plugins/bitbucket_server/impl/impl.go index d59c9a9cb..18b4a4679 100644 --- a/backend/plugins/bitbucket_server/impl/impl.go +++ b/backend/plugins/bitbucket_server/impl/impl.go @@ -123,13 +123,25 @@ func (p BitbucketServer) PrepareTaskData(taskCtx plugin.TaskContext, options map return nil, errors.Default.Wrap(err, "unable to get bitbucket server connection by the given connection ID") } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "unable to get bitbucket server API client instance") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "unable to get bitbucket server API client instance") + } + apiClient = newApiClient } - err = EnrichOptions(taskCtx, op, apiClient.ApiClient) - if err != nil { - return nil, err + if apiClient == nil { + err = EnrichOptions(taskCtx, op, nil) + if err != nil { + return nil, err + } + } else { + err = EnrichOptions(taskCtx, op, apiClient.ApiClient) + if err != nil { + return nil, err + } } regexEnricher := helper.NewRegexEnricher() @@ -239,17 +251,19 @@ func EnrichOptions(taskCtx plugin.TaskContext, } } else { if taskCtx.GetDal().IsErrorNotFound(err) && op.FullName != "" { - var repo *models.BitbucketServerApiRepo - repo, err = tasks.GetApiRepo(op, apiClient) - if err != nil { - return err - } - logger.Debug(fmt.Sprintf("Current repo: %s", repo.Slug)) - scope := repo.ConvertApiScope().(*models.BitbucketServerRepo) - scope.ConnectionId = op.ConnectionId - err = taskCtx.GetDal().CreateIfNotExist(scope) - if err != nil { - return err + if apiClient != nil { + var repo *models.BitbucketServerApiRepo + repo, err = tasks.GetApiRepo(op, apiClient) + if err != nil { + return err + } + logger.Debug(fmt.Sprintf("Current repo: %s", repo.Slug)) + scope := repo.ConvertApiScope().(*models.BitbucketServerRepo) + scope.ConnectionId = op.ConnectionId + err = taskCtx.GetDal().CreateIfNotExist(scope) + if err != nil { + return err + } } } else { return errors.Default.Wrap(err, fmt.Sprintf("fail to find repo %s", op.FullName)) diff --git a/backend/plugins/feishu/impl/impl.go b/backend/plugins/feishu/impl/impl.go index cfe3e1aff..92e0f1571 100644 --- a/backend/plugins/feishu/impl/impl.go +++ b/backend/plugins/feishu/impl/impl.go @@ -109,9 +109,14 @@ func (p Feishu) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]i return nil, err } - apiClient, err := tasks.NewFeishuApiClient(taskCtx, connection) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.NewFeishuApiClient(taskCtx, connection) + if err != nil { + return nil, err + } + apiClient = newApiClient } return &tasks.FeishuTaskData{ Options: &op, diff --git a/backend/plugins/gitee/impl/impl.go b/backend/plugins/gitee/impl/impl.go index 59572fe57..35be389e7 100644 --- a/backend/plugins/gitee/impl/impl.go +++ b/backend/plugins/gitee/impl/impl.go @@ -162,10 +162,15 @@ func (p Gitee) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]in if err != nil { return nil, err } - apiClient, err := tasks.NewGiteeApiClient(taskCtx, connection) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.NewGiteeApiClient(taskCtx, connection) + if err != nil { + return nil, err + } + apiClient = newApiClient } return &tasks.GiteeTaskData{ diff --git a/backend/plugins/icla/impl/impl.go b/backend/plugins/icla/impl/impl.go index 83be4492f..1f327f313 100644 --- a/backend/plugins/icla/impl/impl.go +++ b/backend/plugins/icla/impl/impl.go @@ -71,9 +71,14 @@ func (p Icla) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]int return nil, err } - apiClient, err := errors.Convert01(tasks.NewIclaApiClient(taskCtx)) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := errors.Convert01(tasks.NewIclaApiClient(taskCtx)) + if err != nil { + return nil, err + } + apiClient = newApiClient } return &tasks.IclaTaskData{ diff --git a/backend/plugins/jenkins/api/blueprint_v200.go b/backend/plugins/jenkins/api/blueprint_v200.go index cce0be37d..6f9d1f622 100644 --- a/backend/plugins/jenkins/api/blueprint_v200.go +++ b/backend/plugins/jenkins/api/blueprint_v200.go @@ -49,11 +49,13 @@ func MakeDataSourcePipelinePlanV200( return nil, nil, err } - // needed for the connection to populate its access tokens - // if AppKey authentication method is selected - _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) - if err != nil { - return nil, nil, err + if !skipCollectors { + // needed for the connection to populate its access tokens + // if AppKey authentication method is selected + _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) + if err != nil { + return nil, nil, err + } } plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, scopeDetails, connection) diff --git a/backend/plugins/jenkins/impl/impl.go b/backend/plugins/jenkins/impl/impl.go index 297d9e4b3..7411f7543 100644 --- a/backend/plugins/jenkins/impl/impl.go +++ b/backend/plugins/jenkins/impl/impl.go @@ -126,9 +126,14 @@ func (p Jenkins) PrepareTaskData(taskCtx plugin.TaskContext, options map[string] return nil, err } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, err + } + apiClient = newApiClient } op.ConnectionEndpoint = connection.Endpoint @@ -260,21 +265,23 @@ func EnrichOptions(taskCtx plugin.TaskContext, } } - err = api.GetJob(apiClient, op.JobPath, op.JobName, op.JobFullName, 100, func(job *models.Job, isPath bool) errors.Error { - log.Debug(fmt.Sprintf("Current job: %s", job.FullName)) - op.JobPath = job.Path - op.URL = job.URL - op.Class = job.Class - jenkinsJob := job.ToJenkinsJob() + if apiClient != nil { + err = api.GetJob(apiClient, op.JobPath, op.JobName, op.JobFullName, 100, func(job *models.Job, isPath bool) errors.Error { + log.Debug(fmt.Sprintf("Current job: %s", job.FullName)) + op.JobPath = job.Path + op.URL = job.URL + op.Class = job.Class + jenkinsJob := job.ToJenkinsJob() - jenkinsJob.ConnectionId = op.ConnectionId - jenkinsJob.ScopeConfigId = op.ScopeConfigId + jenkinsJob.ConnectionId = op.ConnectionId + jenkinsJob.ScopeConfigId = op.ScopeConfigId - err = taskCtx.GetDal().CreateIfNotExist(jenkinsJob) - return err - }) - if err != nil { - return err + err = taskCtx.GetDal().CreateIfNotExist(jenkinsJob) + return err + }) + if err != nil { + return err + } } if !strings.HasSuffix(op.JobPath, "/") { diff --git a/backend/plugins/jira/api/blueprint_v200.go b/backend/plugins/jira/api/blueprint_v200.go index f60f5cf13..3d840642c 100644 --- a/backend/plugins/jira/api/blueprint_v200.go +++ b/backend/plugins/jira/api/blueprint_v200.go @@ -48,11 +48,13 @@ func MakeDataSourcePipelinePlanV200( return nil, nil, err } - // needed for the connection to populate its access tokens - // if AppKey authentication method is selected - _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) - if err != nil { - return nil, nil, err + if !skipCollectors { + // needed for the connection to populate its access tokens + // if AppKey authentication method is selected + _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) + if err != nil { + return nil, nil, err + } } plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, scopeDetails, connection) diff --git a/backend/plugins/jira/impl/impl.go b/backend/plugins/jira/impl/impl.go index 8a01b7b11..b7a62da20 100644 --- a/backend/plugins/jira/impl/impl.go +++ b/backend/plugins/jira/impl/impl.go @@ -19,8 +19,6 @@ package impl import ( "fmt" - "net/http" - "github.com/apache/incubator-devlake/core/context" "github.com/apache/incubator-devlake/core/dal" "github.com/apache/incubator-devlake/core/errors" @@ -32,6 +30,7 @@ import ( "github.com/apache/incubator-devlake/plugins/jira/models/migrationscripts" "github.com/apache/incubator-devlake/plugins/jira/tasks" "github.com/apache/incubator-devlake/plugins/jira/tasks/apiv2models" + "net/http" ) var _ interface { @@ -190,9 +189,17 @@ func (p Jira) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]int if err != nil { return nil, errors.Default.Wrap(err, "unable to get Jira connection") } - jiraApiClient, err := tasks.NewJiraApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "failed to create jira api client") + + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + // Jira plugin cannot disable api client when re transforming, + // Because it will fetch + jiraApiClient, err := tasks.NewJiraApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "failed to create jira api client") + } + apiClient = jiraApiClient } if op.BoardId != 0 { @@ -202,16 +209,18 @@ func (p Jira) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]int db := taskCtx.GetDal() err = db.First(&scope, dal.Where("connection_id = ? AND board_id = ?", op.ConnectionId, op.BoardId)) if err != nil && db.IsErrorNotFound(err) { - var board *apiv2models.Board - board, err = api.GetApiJira(&op, jiraApiClient) - if err != nil { - return nil, err - } - logger.Debug(fmt.Sprintf("Current project: %d", board.ID)) - scope = board.ToToolLayer(connection.ID) - err = db.CreateIfNotExist(&scope) - if err != nil { - return nil, err + if apiClient != nil { + var board *apiv2models.Board + board, err = api.GetApiJira(&op, apiClient) + if err != nil { + return nil, err + } + logger.Debug(fmt.Sprintf("Current project: %d", board.ID)) + scope = board.ToToolLayer(connection.ID) + err = db.CreateIfNotExist(&scope) + if err != nil { + return nil, err + } } } if err != nil { @@ -241,14 +250,20 @@ func (p Jira) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]int op.PageSize = 100 } - info, code, err := tasks.GetJiraServerInfo(jiraApiClient) - if err != nil || code != http.StatusOK || info == nil { - return nil, errors.HttpStatus(code).Wrap(err, "fail to get Jira server info") - } taskData := &tasks.JiraTaskData{ - Options: &op, - ApiClient: jiraApiClient, - JiraServerInfo: *info, + Options: &op, + ApiClient: apiClient, + } + if taskData.ApiClient != nil { + info, code, err := tasks.GetJiraServerInfo(taskData.ApiClient) + if err != nil || code != http.StatusOK || info == nil { + return nil, errors.HttpStatus(code).Wrap(err, "fail to get Jira server info") + } + taskData.JiraServerInfo = info + info.ConnectionID = connection.ID + if err := taskCtx.GetDal().CreateOrUpdate(info); err != nil { + return nil, errors.Default.Wrap(err, "create or update jira server info") + } } return taskData, nil diff --git a/backend/plugins/bamboo/tasks/task_data.go b/backend/plugins/jira/models/migrationscripts/20240910_add_table_tool_jira_server_info.go similarity index 57% copy from backend/plugins/bamboo/tasks/task_data.go copy to backend/plugins/jira/models/migrationscripts/20240910_add_table_tool_jira_server_info.go index c5427ac1a..b7fe36708 100644 --- a/backend/plugins/bamboo/tasks/task_data.go +++ b/backend/plugins/jira/models/migrationscripts/20240910_add_table_tool_jira_server_info.go @@ -15,27 +15,27 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tasks +package migrationscripts import ( + "github.com/apache/incubator-devlake/core/context" "github.com/apache/incubator-devlake/core/errors" - helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/bamboo/models" + "github.com/apache/incubator-devlake/core/plugin" + "github.com/apache/incubator-devlake/plugins/jira/models/migrationscripts/archived" ) -type BambooOptions struct { - Options *models.BambooOptions - ApiClient *helper.ApiAsyncClient - RegexEnricher *helper.RegexEnricher +var _ plugin.MigrationScript = (*addJiraServerInfo)(nil) + +type addJiraServerInfo struct{} + +func (*addJiraServerInfo) Up(basicRes context.BasicRes) errors.Error { + return basicRes.GetDal().AutoMigrate(archived.JiraServerInfo{}) +} + +func (*addJiraServerInfo) Version() uint64 { + return 20240910170000 } -func DecodeAndValidateTaskOptions(options map[string]interface{}) (*models.BambooOptions, errors.Error) { - var op models.BambooOptions - if err := helper.Decode(options, &op, nil); err != nil { - return nil, err - } - if op.ConnectionId == 0 { - return nil, errors.Default.New("connectionId is invalid") - } - return &op, nil +func (*addJiraServerInfo) Name() string { + return "add new table _tool_jira_server_info" } diff --git a/backend/plugins/bamboo/tasks/task_data.go b/backend/plugins/jira/models/migrationscripts/archived/jira_server_info.go similarity index 53% copy from backend/plugins/bamboo/tasks/task_data.go copy to backend/plugins/jira/models/migrationscripts/archived/jira_server_info.go index c5427ac1a..78a2d4ad1 100644 --- a/backend/plugins/bamboo/tasks/task_data.go +++ b/backend/plugins/jira/models/migrationscripts/archived/jira_server_info.go @@ -15,27 +15,21 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tasks +package archived -import ( - "github.com/apache/incubator-devlake/core/errors" - helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/bamboo/models" -) - -type BambooOptions struct { - Options *models.BambooOptions - ApiClient *helper.ApiAsyncClient - RegexEnricher *helper.RegexEnricher +type JiraServerInfo struct { + ConnectionID uint64 `json:"connection_id" gorm:"primaryKey"` + BaseURL string `json:"baseUrl"` + BuildDate string `json:"buildDate"` + BuildNumber int `json:"buildNumber"` + DeploymentType string `json:"deploymentType"` + ScmInfo string `json:"ScmInfo"` + ServerTime string `json:"serverTime"` + ServerTitle string `json:"serverTitle"` + Version string `json:"version"` + VersionNumbers []int `json:"versionNumbers" gorm:"type:json;serializer:json"` } -func DecodeAndValidateTaskOptions(options map[string]interface{}) (*models.BambooOptions, errors.Error) { - var op models.BambooOptions - if err := helper.Decode(options, &op, nil); err != nil { - return nil, err - } - if op.ConnectionId == 0 { - return nil, errors.Default.New("connectionId is invalid") - } - return &op, nil +func (JiraServerInfo) TableName() string { + return "_tool_jira_server_infos" } diff --git a/backend/plugins/jira/models/migrationscripts/register.go b/backend/plugins/jira/models/migrationscripts/register.go index 5f32aef7c..8d088b262 100644 --- a/backend/plugins/jira/models/migrationscripts/register.go +++ b/backend/plugins/jira/models/migrationscripts/register.go @@ -53,5 +53,6 @@ func All() []plugin.MigrationScript { new(addIssueFieldTable), new(changeIssueComponentType), new(flushJiraIssues), + new(addJiraServerInfo), } } diff --git a/backend/plugins/jira/models/response_type.go b/backend/plugins/jira/models/response_type.go index 368a4bfda..a84478ba1 100644 --- a/backend/plugins/jira/models/response_type.go +++ b/backend/plugins/jira/models/response_type.go @@ -25,6 +25,7 @@ const DeploymentServer DeploymentType = "Server" const LocaleEnUS Locale = "en_US" type JiraServerInfo struct { + ConnectionID uint64 `json:"connection_id" gorm:"primaryKey"` // for db store BaseURL string `json:"baseUrl"` BuildDate string `json:"buildDate"` BuildNumber int `json:"buildNumber"` @@ -33,7 +34,11 @@ type JiraServerInfo struct { ServerTime string `json:"serverTime"` ServerTitle string `json:"serverTitle"` Version string `json:"version"` - VersionNumbers []int `json:"versionNumbers"` + VersionNumbers []int `json:"versionNumbers" gorm:"type:json;serializer:json"` +} + +func (jiraServerInfo JiraServerInfo) IsDeploymentServer() bool { + return jiraServerInfo.DeploymentType == DeploymentServer } type JiraErrorInfo struct { diff --git a/backend/plugins/jira/tasks/account_collector.go b/backend/plugins/jira/tasks/account_collector.go index fcf85dd6a..2260a4ac4 100644 --- a/backend/plugins/jira/tasks/account_collector.go +++ b/backend/plugins/jira/tasks/account_collector.go @@ -66,7 +66,12 @@ func CollectAccounts(taskCtx plugin.SubTaskContext) errors.Error { } queryKey := "accountId" urlTemplate := "api/2/user" - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag { queryKey = "key" } diff --git a/backend/plugins/jira/tasks/epic_collector.go b/backend/plugins/jira/tasks/epic_collector.go index 959b0e3c8..b6bd8ed8f 100644 --- a/backend/plugins/jira/tasks/epic_collector.go +++ b/backend/plugins/jira/tasks/epic_collector.go @@ -22,13 +22,11 @@ import ( "reflect" "strings" + "encoding/json" "github.com/apache/incubator-devlake/core/dal" "github.com/apache/incubator-devlake/core/errors" "github.com/apache/incubator-devlake/core/plugin" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/jira/models" - - "encoding/json" "io" "net/http" "net/url" @@ -51,7 +49,11 @@ func CollectEpics(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*JiraTaskData) logger := taskCtx.GetLogger() batchSize := 100 - if data.JiraServerInfo.DeploymentType == models.DeploymentServer && len(data.JiraServerInfo.VersionNumbers) == 3 && data.JiraServerInfo.VersionNumbers[0] <= 8 { + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag && len(data.JiraServerInfo.VersionNumbers) == 3 && data.JiraServerInfo.VersionNumbers[0] <= 8 { batchSize = 1 } epicIterator, err := GetEpicKeysIterator(db, data, batchSize) @@ -130,12 +132,12 @@ func GetEpicKeysIterator(db dal.Dal, data *JiraTaskData, batchSize int) (api.Ite dal.Join(` LEFT JOIN _tool_jira_board_issues bi ON ( i.connection_id = bi.connection_id - AND + AND i.issue_id = bi.issue_id )`), dal.Where(` i.connection_id = ? - AND + AND bi.board_id = ? AND i.epic_key != '' diff --git a/backend/plugins/jira/tasks/issue_changelog_collector.go b/backend/plugins/jira/tasks/issue_changelog_collector.go index 76c1eef38..2c286574c 100644 --- a/backend/plugins/jira/tasks/issue_changelog_collector.go +++ b/backend/plugins/jira/tasks/issue_changelog_collector.go @@ -29,7 +29,6 @@ import ( "github.com/apache/incubator-devlake/core/log" "github.com/apache/incubator-devlake/core/plugin" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/jira/models" "github.com/apache/incubator-devlake/plugins/jira/tasks/apiv2models" ) @@ -47,11 +46,16 @@ var CollectIssueChangelogsMeta = plugin.SubTaskMeta{ func CollectIssueChangelogs(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*JiraTaskData) - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + db := taskCtx.GetDal() + + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, db, data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag { return nil } logger := taskCtx.GetLogger() - db := taskCtx.GetDal() apiCollector, err := api.NewStatefulApiCollector(api.RawDataSubTaskArgs{ Ctx: taskCtx, diff --git a/backend/plugins/jira/tasks/issue_changelog_extractor.go b/backend/plugins/jira/tasks/issue_changelog_extractor.go index a49142e3f..0cd9d4f65 100644 --- a/backend/plugins/jira/tasks/issue_changelog_extractor.go +++ b/backend/plugins/jira/tasks/issue_changelog_extractor.go @@ -23,7 +23,6 @@ import ( "github.com/apache/incubator-devlake/core/errors" "github.com/apache/incubator-devlake/core/plugin" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/jira/models" "github.com/apache/incubator-devlake/plugins/jira/tasks/apiv2models" ) @@ -39,7 +38,12 @@ var ExtractIssueChangelogsMeta = plugin.SubTaskMeta{ func ExtractIssueChangelogs(subtaskCtx plugin.SubTaskContext) errors.Error { data := subtaskCtx.GetData().(*JiraTaskData) - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, subtaskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag { return nil } connectionId := data.Options.ConnectionId diff --git a/backend/plugins/jira/tasks/issue_collector.go b/backend/plugins/jira/tasks/issue_collector.go index 84ac2d727..73f354969 100644 --- a/backend/plugins/jira/tasks/issue_collector.go +++ b/backend/plugins/jira/tasks/issue_collector.go @@ -172,7 +172,12 @@ func getTimeZone(taskCtx plugin.SubTaskContext) (*time.Location, errors.Error) { var resp *http.Response var path string var query url.Values - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return nil, err + } + + if isServerFlag { path = "api/2/user" query = url.Values{"username": []string{conn.Username}} } else { diff --git a/backend/plugins/jira/tasks/issue_comment_collector.go b/backend/plugins/jira/tasks/issue_comment_collector.go index 5ef2777be..14bff5dd2 100644 --- a/backend/plugins/jira/tasks/issue_comment_collector.go +++ b/backend/plugins/jira/tasks/issue_comment_collector.go @@ -29,7 +29,6 @@ import ( "github.com/apache/incubator-devlake/core/log" "github.com/apache/incubator-devlake/core/plugin" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/jira/models" "github.com/apache/incubator-devlake/plugins/jira/tasks/apiv2models" ) @@ -47,7 +46,11 @@ var CollectIssueCommentsMeta = plugin.SubTaskMeta{ func CollectIssueComments(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*JiraTaskData) - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag { return nil } logger := taskCtx.GetLogger() diff --git a/backend/plugins/jira/tasks/issue_comment_extractor.go b/backend/plugins/jira/tasks/issue_comment_extractor.go index e53828853..ada1a42ac 100644 --- a/backend/plugins/jira/tasks/issue_comment_extractor.go +++ b/backend/plugins/jira/tasks/issue_comment_extractor.go @@ -22,7 +22,6 @@ import ( "github.com/apache/incubator-devlake/core/errors" "github.com/apache/incubator-devlake/core/plugin" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/jira/models" "github.com/apache/incubator-devlake/plugins/jira/tasks/apiv2models" ) @@ -38,7 +37,11 @@ var ExtractIssueCommentsMeta = plugin.SubTaskMeta{ func ExtractIssueComments(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*JiraTaskData) - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag { return nil } connectionId := data.Options.ConnectionId diff --git a/backend/plugins/jira/tasks/issue_type_collector.go b/backend/plugins/jira/tasks/issue_type_collector.go index c867316b7..5c4432d10 100644 --- a/backend/plugins/jira/tasks/issue_type_collector.go +++ b/backend/plugins/jira/tasks/issue_type_collector.go @@ -24,7 +24,6 @@ import ( "github.com/apache/incubator-devlake/core/errors" "github.com/apache/incubator-devlake/core/plugin" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" - "github.com/apache/incubator-devlake/plugins/jira/models" ) const RAW_ISSUE_TYPE_TABLE = "jira_api_issue_types" @@ -45,7 +44,11 @@ func CollectIssueTypes(taskCtx plugin.SubTaskContext) errors.Error { logger.Info("collect issue_types") urlTemplate := "api/3/issuetype" - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err + } + if isServerFlag { urlTemplate = "api/2/issuetype" } collector, err := api.NewApiCollector(api.ApiCollectorArgs{ diff --git a/backend/plugins/jira/tasks/shared.go b/backend/plugins/jira/tasks/shared.go index cdd118dd1..0fd0e5631 100644 --- a/backend/plugins/jira/tasks/shared.go +++ b/backend/plugins/jira/tasks/shared.go @@ -18,9 +18,11 @@ limitations under the License. package tasks import ( + "github.com/apache/incubator-devlake/core/dal" "github.com/apache/incubator-devlake/core/errors" "github.com/apache/incubator-devlake/core/models/domainlayer/ticket" "github.com/apache/incubator-devlake/helpers/pluginhelper/api" + "github.com/apache/incubator-devlake/plugins/jira/models" "net/http" ) @@ -46,3 +48,37 @@ func getStdStatus(statusKey string) string { return ticket.IN_PROGRESS } } + +func isServer(jiraServerInfo *models.JiraServerInfo, apiclient *api.ApiAsyncClient, db dal.Dal, connectionID uint64) (bool, errors.Error) { + if jiraServerInfo != nil { + return jiraServerInfo.IsDeploymentServer(), nil + } + // try to fetch jiraServerInfo from remote api + if apiclient != nil { + info, code, err := GetJiraServerInfo(apiclient) + if err != nil || code != http.StatusOK || info == nil { + return false, errors.HttpStatus(code).Wrap(err, "fail to get Jira server info") + } + return info.IsDeploymentServer(), nil + } + // fetch from db + info, err := getJiraServerInfoFromDB(db, connectionID) + if err != nil { + return false, err + } + if info == nil { + return false, nil + } + return info.IsDeploymentServer(), nil +} + +func getJiraServerInfoFromDB(db dal.Dal, connectionID uint64) (*models.JiraServerInfo, errors.Error) { + var info models.JiraServerInfo + if err := db.First(&info, dal.Where("connection_id = ?", connectionID)); err != nil { + if db.IsErrorNotFound(err) { + return nil, nil + } + return nil, err + } + return &info, nil +} diff --git a/backend/plugins/jira/tasks/sprint_extractor.go b/backend/plugins/jira/tasks/sprint_extractor.go index 21276353d..b1012dcec 100644 --- a/backend/plugins/jira/tasks/sprint_extractor.go +++ b/backend/plugins/jira/tasks/sprint_extractor.go @@ -39,9 +39,10 @@ var ExtractSprintsMeta = plugin.SubTaskMeta{ func ExtractSprints(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*JiraTaskData) - isServer := false - if data.JiraServerInfo.DeploymentType == models.DeploymentServer { - isServer = true + + isServerFlag, err := isServer(data.JiraServerInfo, data.ApiClient, taskCtx.GetDal(), data.Options.ConnectionId) + if err != nil { + return err } extractor, err := api.NewApiExtractor(api.ApiExtractorArgs{ @@ -64,7 +65,7 @@ func ExtractSprints(taskCtx plugin.SubTaskContext) errors.Error { BoardId: data.Options.BoardId, SprintId: sprint.ID, } - return []interface{}{sprint.ToToolLayer(data.Options.ConnectionId, isServer), &boardSprint}, nil + return []interface{}{sprint.ToToolLayer(data.Options.ConnectionId, isServerFlag), &boardSprint}, nil }, }) diff --git a/backend/plugins/jira/tasks/task_data.go b/backend/plugins/jira/tasks/task_data.go index 1b0580396..2f9c12e86 100644 --- a/backend/plugins/jira/tasks/task_data.go +++ b/backend/plugins/jira/tasks/task_data.go @@ -36,7 +36,7 @@ type JiraOptions struct { type JiraTaskData struct { Options *JiraOptions ApiClient *api.ApiAsyncClient - JiraServerInfo models.JiraServerInfo + JiraServerInfo *models.JiraServerInfo } type JiraApiParams models.JiraApiParams diff --git a/backend/plugins/opsgenie/impl/impl.go b/backend/plugins/opsgenie/impl/impl.go index fc234e7aa..5785d53ff 100644 --- a/backend/plugins/opsgenie/impl/impl.go +++ b/backend/plugins/opsgenie/impl/impl.go @@ -123,15 +123,20 @@ func (p Opsgenie) PrepareTaskData(taskCtx plugin.TaskContext, options map[string return nil, errors.Default.Wrap(err, "unable to get Opsgenie connection by the given connection ID") } - client, err := helper.NewApiClientFromConnection(taskCtx.GetContext(), taskCtx, connection) - - if err != nil { - return nil, err - } - asyncClient, err := helper.CreateAsyncApiClient(taskCtx, client, nil) - if err != nil { - return nil, err + var asyncClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + client, err := helper.NewApiClientFromConnection(taskCtx.GetContext(), taskCtx, connection) + if err != nil { + return nil, err + } + newAsyncClient, err := helper.CreateAsyncApiClient(taskCtx, client, nil) + if err != nil { + return nil, err + } + asyncClient = newAsyncClient } + return &tasks.OpsgenieTaskData{ Options: op, Client: asyncClient, diff --git a/backend/plugins/pagerduty/impl/impl.go b/backend/plugins/pagerduty/impl/impl.go index 8ed6b21b9..b237b30e4 100644 --- a/backend/plugins/pagerduty/impl/impl.go +++ b/backend/plugins/pagerduty/impl/impl.go @@ -109,14 +109,19 @@ func (p PagerDuty) PrepareTaskData(taskCtx plugin.TaskContext, options map[strin return nil, errors.Default.Wrap(err, "unable to get Pagerduty connection by the given connection ID") } - client, err := helper.NewApiClientFromConnection(taskCtx.GetContext(), taskCtx, connection) - - if err != nil { - return nil, err - } - asyncClient, err := helper.CreateAsyncApiClient(taskCtx, client, nil) - if err != nil { - return nil, err + var asyncClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + client, err := helper.NewApiClientFromConnection(taskCtx.GetContext(), taskCtx, connection) + + if err != nil { + return nil, err + } + newAsyncClient, err := helper.CreateAsyncApiClient(taskCtx, client, nil) + if err != nil { + return nil, err + } + asyncClient = newAsyncClient } return &tasks.PagerDutyTaskData{ Options: op, diff --git a/backend/plugins/slack/impl/impl.go b/backend/plugins/slack/impl/impl.go index 1b8e40940..8b3de9142 100644 --- a/backend/plugins/slack/impl/impl.go +++ b/backend/plugins/slack/impl/impl.go @@ -108,9 +108,14 @@ func (p Slack) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]in return nil, err } - apiClient, err := tasks.NewSlackApiClient(taskCtx, connection) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.NewSlackApiClient(taskCtx, connection) + if err != nil { + return nil, err + } + apiClient = newApiClient } return &tasks.SlackTaskData{ Options: &op, diff --git a/backend/plugins/sonarqube/api/blueprint_v200.go b/backend/plugins/sonarqube/api/blueprint_v200.go index e2995aa65..b129b347b 100644 --- a/backend/plugins/sonarqube/api/blueprint_v200.go +++ b/backend/plugins/sonarqube/api/blueprint_v200.go @@ -51,11 +51,13 @@ func MakeDataSourcePipelinePlanV200( return nil, nil, err } - // needed for the connection to populate its access tokens - // if AppKey authentication method is selected - _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) - if err != nil { - return nil, nil, err + if !skipCollectors { + // needed for the connection to populate its access tokens + // if AppKey authentication method is selected + _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes, connection) + if err != nil { + return nil, nil, err + } } plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, scopeDetails, connection) diff --git a/backend/plugins/sonarqube/impl/impl.go b/backend/plugins/sonarqube/impl/impl.go index a364435b1..b6d214032 100644 --- a/backend/plugins/sonarqube/impl/impl.go +++ b/backend/plugins/sonarqube/impl/impl.go @@ -126,29 +126,37 @@ func (p Sonarqube) PrepareTaskData(taskCtx plugin.TaskContext, options map[strin return nil, errors.Default.Wrap(err, "unable to get Sonarqube connection by the given connection ID") } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "unable to get Sonarqube API client instance") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "unable to get Sonarqube API client instance") + } + apiClient = newApiClient } taskData := &tasks.SonarqubeTaskData{ Options: op, ApiClient: apiClient, TaskStartTime: time.Now(), } - // even we have project in _tool_sonaqube_projects, we still need to collect project to update LastAnalysisDate - var apiProject *models.SonarqubeApiProject - apiProject, err = api.GetApiProject(op.ProjectKey, apiClient) - if err != nil { - return nil, err - } - logger.Debug(fmt.Sprintf("Current project: %s", apiProject.ProjectKey)) - scope := apiProject.ConvertApiScope() - scope.ConnectionId = op.ConnectionId - err = taskCtx.GetDal().CreateOrUpdate(&scope) - if err != nil { - return nil, err + if apiClient != nil { + // even we have project in _tool_sonarqube_projects, we still need to collect project to update LastAnalysisDate + var apiProject *models.SonarqubeApiProject + apiProject, err = api.GetApiProject(op.ProjectKey, apiClient) + if err != nil { + return nil, err + } + logger.Debug(fmt.Sprintf("Current project: %s", apiProject.ProjectKey)) + scope := apiProject.ConvertApiScope() + scope.ConnectionId = op.ConnectionId + + err = taskCtx.GetDal().CreateOrUpdate(&scope) + if err != nil { + return nil, err + } + taskData.LastAnalysisDate = scope.LastAnalysisDate.ToNullableTime() } - taskData.LastAnalysisDate = scope.LastAnalysisDate.ToNullableTime() return taskData, nil } diff --git a/backend/plugins/tapd/impl/impl.go b/backend/plugins/tapd/impl/impl.go index 0cd823601..2885a4337 100644 --- a/backend/plugins/tapd/impl/impl.go +++ b/backend/plugins/tapd/impl/impl.go @@ -204,9 +204,14 @@ func (p Tapd) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]int if connection.RateLimitPerHour == 0 { connection.RateLimitPerHour = 3600 } - tapdApiClient, err := tasks.NewTapdApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "failed to create tapd api client") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + tapdApiClient, err := tasks.NewTapdApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "failed to create tapd api client") + } + apiClient = tapdApiClient } if op.WorkspaceId != 0 { @@ -238,7 +243,7 @@ func (p Tapd) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]int op.CstZone = cstZone taskData := &tasks.TapdTaskData{ Options: op, - ApiClient: tapdApiClient, + ApiClient: apiClient, Connection: connection, } return taskData, nil diff --git a/backend/plugins/teambition/impl/impl.go b/backend/plugins/teambition/impl/impl.go index d31a58736..662cace0f 100644 --- a/backend/plugins/teambition/impl/impl.go +++ b/backend/plugins/teambition/impl/impl.go @@ -142,9 +142,14 @@ func (p Teambition) PrepareTaskData(taskCtx plugin.TaskContext, options map[stri return nil, errors.Default.Wrap(err, "unable to get Teambition connection by the given connection ID") } - apiClient, err := tasks.NewTeambitionApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "unable to get Teambition API client instance") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.NewTeambitionApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "unable to get Teambition API client instance") + } + apiClient = newApiClient } taskData := &tasks.TeambitionTaskData{ Options: op, diff --git a/backend/plugins/trello/impl/impl.go b/backend/plugins/trello/impl/impl.go index 35adaa2c1..b3a0f088d 100644 --- a/backend/plugins/trello/impl/impl.go +++ b/backend/plugins/trello/impl/impl.go @@ -116,9 +116,14 @@ func (p Trello) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]i if err != nil { return nil, errors.Default.Wrap(err, "error getting connection for Trello plugin") } - apiClient, err := tasks.CreateApiClient(taskCtx, connection) - if err != nil { - return nil, err + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.CreateApiClient(taskCtx, connection) + if err != nil { + return nil, err + } + apiClient = newApiClient } return &tasks.TrelloTaskData{ Options: &op, diff --git a/backend/plugins/zentao/impl/impl.go b/backend/plugins/zentao/impl/impl.go index 4317fa574..5aa74c966 100644 --- a/backend/plugins/zentao/impl/impl.go +++ b/backend/plugins/zentao/impl/impl.go @@ -19,6 +19,8 @@ package impl import ( "fmt" + "net/url" + "strings" "github.com/apache/incubator-devlake/core/context" "github.com/apache/incubator-devlake/core/dal" @@ -182,9 +184,14 @@ func (p Zentao) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]i return nil, errors.Default.Wrap(err, "unable to get Zentao connection by the given connection ID: %v") } - apiClient, err := tasks.NewZentaoApiClient(taskCtx, connection) - if err != nil { - return nil, errors.Default.Wrap(err, "unable to get Zentao API client instance: %v") + var apiClient *helper.ApiAsyncClient + syncPolicy := taskCtx.SyncPolicy() + if !syncPolicy.SkipCollectors { + newApiClient, err := tasks.NewZentaoApiClient(taskCtx, connection) + if err != nil { + return nil, errors.Default.Wrap(err, "unable to get Zentao API client instance: %v") + } + apiClient = newApiClient } if op.ScopeConfig == nil && op.ScopeConfigId != 0 { @@ -203,36 +210,64 @@ func (p Zentao) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]i AccountCache: tasks.NewAccountCache(taskCtx.GetDal(), op.ConnectionId), } - if connection.DbUrl != "" { - if connection.DbLoggingLevel == "" { - connection.DbLoggingLevel = taskCtx.GetConfig("DB_LOGGING_LEVEL") - } + if !syncPolicy.SkipCollectors { + if connection.DbUrl != "" { + if connection.DbLoggingLevel == "" { + connection.DbLoggingLevel = taskCtx.GetConfig("DB_LOGGING_LEVEL") + } - if connection.DbIdleConns == 0 { - connection.DbIdleConns = taskCtx.GetConfigReader().GetInt("DB_IDLE_CONNS") - } + if connection.DbIdleConns == 0 { + connection.DbIdleConns = taskCtx.GetConfigReader().GetInt("DB_IDLE_CONNS") + } - if connection.DbMaxConns == 0 { - connection.DbMaxConns = taskCtx.GetConfigReader().GetInt("DB_MAX_CONNS") - } + if connection.DbMaxConns == 0 { + connection.DbMaxConns = taskCtx.GetConfigReader().GetInt("DB_MAX_CONNS") + } - v := viper.New() - v.Set("DB_URL", connection.DbUrl) - v.Set("DB_LOGGING_LEVEL", connection.DbLoggingLevel) - v.Set("DB_IDLE_CONNS", connection.DbIdleConns) - v.Set("DbMaxConns", connection.DbMaxConns) + v := viper.New() + v.Set("DB_URL", connection.DbUrl) + v.Set("DB_LOGGING_LEVEL", connection.DbLoggingLevel) + v.Set("DB_IDLE_CONNS", connection.DbIdleConns) + v.Set("DbMaxConns", connection.DbMaxConns) - rgorm, err := runner.NewGormDb(v, taskCtx.GetLogger()) - if err != nil { - return nil, errors.Default.Wrap(err, fmt.Sprintf("failed to connect to the zentao remote databases %s", connection.DbUrl)) + rgorm, err := runner.NewGormDb(v, taskCtx.GetLogger()) + if err != nil { + return nil, errors.Default.Wrap(err, fmt.Sprintf("failed to connect to the zentao remote databases %s", connection.DbUrl)) + } + + data.RemoteDb = dalgorm.NewDalgorm(rgorm) } + } - data.RemoteDb = dalgorm.NewDalgorm(rgorm) + endpoint := connection.Endpoint + if data.ApiClient != nil { + endpoint = data.ApiClient.GetEndpoint() + } + homepage, err := getZentaoHomePage(endpoint) + if err != nil { + return data, errors.Convert(err) } + data.HomePageURL = homepage return data, nil } +// getZentaoHomePage receive endpoint like "http://54.158.1.10:30001/api.php/v1/" and return zentao's homepage like "http://54.158.1.10:30001/" +func getZentaoHomePage(endpoint string) (string, error) { + if endpoint == "" { + return "", errors.Default.New("empty endpoint") + } + endpointURL, err := url.Parse(endpoint) + if err != nil { + return "", err + } else { + protocol := endpointURL.Scheme + host := endpointURL.Host + zentaoPath, _, _ := strings.Cut(endpointURL.Path, "/api.php/v1") + return fmt.Sprintf("%s://%s%s", protocol, host, zentaoPath), nil + } +} + // RootPkgPath information lost when compiled as plugin(.so) func (p Zentao) RootPkgPath() string { return "github.com/apache/incubator-devlake/plugins/zentao" diff --git a/backend/plugins/zentao/tasks/execution_convertor.go b/backend/plugins/zentao/tasks/execution_convertor.go index 41d80d3bb..8fda2676e 100644 --- a/backend/plugins/zentao/tasks/execution_convertor.go +++ b/backend/plugins/zentao/tasks/execution_convertor.go @@ -44,7 +44,6 @@ var ConvertExecutionMeta = plugin.SubTaskMeta{ func ConvertExecutions(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*ZentaoTaskData) db := taskCtx.GetDal() - logger := taskCtx.GetLogger() executionIdGen := didgen.NewDomainIdGenerator(&models.ZentaoExecution{}) projectIdGen := didgen.NewDomainIdGenerator(&models.ZentaoProject{}) cursor, err := db.Cursor( @@ -54,12 +53,6 @@ func ConvertExecutions(taskCtx plugin.SubTaskContext) errors.Error { if err != nil { return err } - - homePage, getZentaoHomePageErr := getZentaoHomePage(data.ApiClient.GetEndpoint()) - if getZentaoHomePageErr != nil { - logger.Error(getZentaoHomePageErr, "get zentao homepage") - return errors.Default.WrapRaw(getZentaoHomePageErr) - } defer cursor.Close() convertor, err := api.NewDataConverter(api.DataConverterArgs{ InputRowType: reflect.TypeOf(models.ZentaoExecution{}), @@ -91,7 +84,7 @@ func ConvertExecutions(taskCtx plugin.SubTaskContext) errors.Error { Id: executionIdGen.Generate(toolExecution.ConnectionId, toolExecution.Id), }, Name: toolExecution.Name, - Url: fmt.Sprintf("%s/execution-view-%d.html", homePage, toolExecution.Id), + Url: fmt.Sprintf("%s/execution-view-%d.html", data.HomePageURL, toolExecution.Id), Status: domainStatus, StartedDate: toolExecution.RealBegan.ToNullableTime(), EndedDate: toolExecution.PlanEnd.ToNullableTime(), diff --git a/backend/plugins/zentao/tasks/project_convertor.go b/backend/plugins/zentao/tasks/project_convertor.go index b09ef9405..d45a00758 100644 --- a/backend/plugins/zentao/tasks/project_convertor.go +++ b/backend/plugins/zentao/tasks/project_convertor.go @@ -45,7 +45,6 @@ var ConvertProjectMeta = plugin.SubTaskMeta{ func ConvertProjects(taskCtx plugin.SubTaskContext) errors.Error { data := taskCtx.GetData().(*ZentaoTaskData) db := taskCtx.GetDal() - logger := taskCtx.GetLogger() boardIdGen := didgen.NewDomainIdGenerator(&models.ZentaoProject{}) cursor, err := db.Cursor( dal.From(&models.ZentaoProject{}), @@ -55,11 +54,6 @@ func ConvertProjects(taskCtx plugin.SubTaskContext) errors.Error { return err } defer cursor.Close() - homePage, getZentaoHomePageErr := getZentaoHomePage(data.ApiClient.GetEndpoint()) - if getZentaoHomePageErr != nil { - logger.Error(getZentaoHomePageErr, "get zentao homepage") - return errors.Default.WrapRaw(getZentaoHomePageErr) - } convertor, err := api.NewDataConverter(api.DataConverterArgs{ InputRowType: reflect.TypeOf(models.ZentaoProject{}), Input: cursor, @@ -79,7 +73,7 @@ func ConvertProjects(taskCtx plugin.SubTaskContext) errors.Error { Description: toolProject.Description, CreatedDate: toolProject.OpenedDate.ToNullableTime(), Type: "scrum", - Url: fmt.Sprintf("%s/project-index-%d.html", homePage, data.Options.ProjectId), + Url: fmt.Sprintf("%s/project-index-%d.html", data.HomePageURL, data.Options.ProjectId), } results := make([]interface{}, 0) results = append(results, domainBoard) diff --git a/backend/plugins/zentao/tasks/shared.go b/backend/plugins/zentao/tasks/shared.go index aa1140573..de4de2307 100644 --- a/backend/plugins/zentao/tasks/shared.go +++ b/backend/plugins/zentao/tasks/shared.go @@ -339,19 +339,3 @@ func extractIdFromLogComment(logCommentType string, comment string) ([]string, e } return ret, nil } - -// getZentaoHomePage receive endpoint like "http://54.158.1.10:30001/api.php/v1/" and return zentao's homepage like "http://54.158.1.10:30001/" -func getZentaoHomePage(endpoint string) (string, error) { - if endpoint == "" { - return "", errors.Default.New("empty endpoint") - } - endpointURL, err := url.Parse(endpoint) - if err != nil { - return "", err - } else { - protocol := endpointURL.Scheme - host := endpointURL.Host - zentaoPath, _, _ := strings.Cut(endpointURL.Path, "/api.php/v1") - return fmt.Sprintf("%s://%s%s", protocol, host, zentaoPath), nil - } -} diff --git a/backend/plugins/zentao/tasks/task_data.go b/backend/plugins/zentao/tasks/task_data.go index 26bc9734c..a6a097f21 100644 --- a/backend/plugins/zentao/tasks/task_data.go +++ b/backend/plugins/zentao/tasks/task_data.go @@ -57,6 +57,7 @@ type ZentaoTaskData struct { Bugs map[int64]struct{} AccountCache *AccountCache ApiClient *helper.ApiAsyncClient + HomePageURL string } func DecodeAndValidateTaskOptions(options map[string]interface{}) (*ZentaoOptions, error) {
