You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by wa...@apache.org on 2023/02/17 05:16:08 UTC
[incubator-devlake] branch main updated: feat: bamboo connection (#4435)
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new 641607837 feat: bamboo connection (#4435)
641607837 is described below
commit 64160783720e08d2c5f2bea4fa795f94832775cf
Author: mappjzc <zh...@merico.dev>
AuthorDate: Fri Feb 17 13:16:03 2023 +0800
feat: bamboo connection (#4435)
* feat: bamboo connection
Add connection for bamboo
Nddtfjiang <zh...@merico.dev>
* fix: fix for review
fix for review
Nddtfjiang <zh...@merico.dev>
---
backend/plugins/bamboo/api/connection.go | 149 ++++++++++++++++++++
backend/plugins/bamboo/api/init.go | 37 +++++
backend/plugins/bamboo/bamboo.go | 42 ++++++
backend/plugins/bamboo/impl/impl.go | 150 +++++++++++++++++++++
backend/plugins/bamboo/models/connection.go | 128 ++++++++++++++++++
.../migrationscripts/20230216_add_init_tables.go | 42 ++++++
.../models/migrationscripts/archived/connection.go | 77 +++++++++++
.../bamboo/models/migrationscripts/register.go | 29 ++++
backend/plugins/bamboo/tasks/api_client.go | 72 ++++++++++
backend/plugins/bamboo/tasks/task_data.go | 52 +++++++
10 files changed, 778 insertions(+)
diff --git a/backend/plugins/bamboo/api/connection.go b/backend/plugins/bamboo/api/connection.go
new file mode 100644
index 000000000..c516c3206
--- /dev/null
+++ b/backend/plugins/bamboo/api/connection.go
@@ -0,0 +1,149 @@
+/*
+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 api
+
+import (
+ "context"
+ "net/http"
+
+ "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/bamboo/models"
+ "github.com/apache/incubator-devlake/server/api/shared"
+)
+
+type BambooTestConnResponse struct {
+ shared.ApiBody
+ Connection *models.BambooConn
+}
+
+// @Summary test bamboo connection
+// @Description Test bamboo Connection
+// @Tags plugins/bamboo
+// @Param body body models.BambooConn true "json body"
+// @Success 200 {object} BambooTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/Bamboo/test [POST]
+func TestConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ var err errors.Error
+ var connection models.BambooConn
+ if err = api.Decode(input.Body, &connection, vld); err != nil {
+ return nil, err
+ }
+
+ // test connection
+ _, err = api.NewApiClientFromConnection(
+ context.TODO(),
+ basicRes,
+ &connection,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ body := BambooTestConnResponse{}
+ body.Success = true
+ body.Message = "success"
+ body.Connection = &connection
+
+ return &plugin.ApiResourceOutput{Body: body, Status: http.StatusOK}, nil
+}
+
+// @Summary create bamboo connection
+// @Description Create bamboo connection
+// @Tags plugins/bamboo
+// @Param body body models.BambooConnection true "json body"
+// @Success 200 {object} models.BambooConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internel Error"
+// @Router /plugins/bamboo/connections [POST]
+func PostConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
+ // update from request and save to database
+ connection := &models.BambooConnection{}
+ err := connectionHelper.Create(connection, input)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: connection, Status: http.StatusOK}, nil
+}
+
+// @Summary patch bamboo connection
+// @Description Patch bamboo connection
+// @Tags plugins/bamboo
+// @Param body body models.BambooConnection true "json body"
+// @Success 200 {object} models.BambooConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internel Error"
+// @Router /plugins/bamboo/connections/{connectionId} [PATCH]
+func PatchConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.BambooConnection{}
+ err := connectionHelper.Patch(connection, input)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: connection}, nil
+}
+
+// @Summary delete a bamboo connection
+// @Description Delete a bamboo connection
+// @Tags plugins/bamboo
+// @Success 200 {object} models.BambooConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internel Error"
+// @Router /plugins/bamboo/connections/{connectionId} [DELETE]
+func DeleteConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.BambooConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, err
+ }
+ err = connectionHelper.Delete(connection)
+ return &plugin.ApiResourceOutput{Body: connection}, err
+}
+
+// @Summary get all bamboo connections
+// @Description Get all bamboo connections
+// @Tags plugins/bamboo
+// @Success 200 {object} []models.BambooConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internel Error"
+// @Router /plugins/bamboo/connections [GET]
+func ListConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
+ var connections []models.BambooConnection
+ err := connectionHelper.List(&connections)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: connections, Status: http.StatusOK}, nil
+}
+
+// @Summary get bamboo connection detail
+// @Description Get bamboo connection detail
+// @Tags plugins/bamboo
+// @Success 200 {object} models.BambooConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internel Error"
+// @Router /plugins/bamboo/connections/{connectionId} [GET]
+func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.BambooConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ return &plugin.ApiResourceOutput{Body: connection}, err
+}
diff --git a/backend/plugins/bamboo/api/init.go b/backend/plugins/bamboo/api/init.go
new file mode 100644
index 000000000..cd019a36f
--- /dev/null
+++ b/backend/plugins/bamboo/api/init.go
@@ -0,0 +1,37 @@
+/*
+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 api
+
+import (
+ "github.com/apache/incubator-devlake/core/context"
+ helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/go-playground/validator/v10"
+)
+
+var vld *validator.Validate
+var connectionHelper *helper.ConnectionApiHelper
+var basicRes context.BasicRes
+
+func Init(br context.BasicRes) {
+ basicRes = br
+ vld = validator.New()
+ connectionHelper = helper.NewConnectionHelper(
+ basicRes,
+ vld,
+ )
+}
diff --git a/backend/plugins/bamboo/bamboo.go b/backend/plugins/bamboo/bamboo.go
new file mode 100644
index 000000000..076323e69
--- /dev/null
+++ b/backend/plugins/bamboo/bamboo.go
@@ -0,0 +1,42 @@
+/*
+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 main
+
+import (
+ "github.com/apache/incubator-devlake/core/runner"
+ "github.com/apache/incubator-devlake/plugins/bamboo/impl"
+ "github.com/spf13/cobra"
+)
+
+// PluginEntry exports for Framework to search and load
+var PluginEntry impl.Bamboo //nolint
+
+// standalone mode for debugging
+func main() {
+ bambooCmd := &cobra.Command{Use: "bamboo"}
+ connectionId := bambooCmd.Flags().Uint64P("Connection-id", "c", 0, "bamboo connection id")
+ projectId := bambooCmd.Flags().IntP("project-id", "p", 0, "bamboo project id")
+ _ = bambooCmd.MarkFlagRequired("project-id")
+ bambooCmd.Run = func(cmd *cobra.Command, args []string) {
+ runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+ "connectionId": *connectionId,
+ "projectId": *projectId,
+ })
+ }
+ runner.RunCmd(bambooCmd)
+}
diff --git a/backend/plugins/bamboo/impl/impl.go b/backend/plugins/bamboo/impl/impl.go
new file mode 100644
index 000000000..a7c922d88
--- /dev/null
+++ b/backend/plugins/bamboo/impl/impl.go
@@ -0,0 +1,150 @@
+/*
+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 impl
+
+import (
+ "fmt"
+
+ "github.com/apache/incubator-devlake/core/context"
+ "github.com/apache/incubator-devlake/core/dal"
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/core/plugin"
+ helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/bamboo/api"
+ "github.com/apache/incubator-devlake/plugins/bamboo/models"
+ "github.com/apache/incubator-devlake/plugins/bamboo/models/migrationscripts"
+ "github.com/apache/incubator-devlake/plugins/bamboo/tasks"
+)
+
+// make sure interface is implemented
+var _ interface {
+ plugin.PluginMeta
+ plugin.PluginInit
+ plugin.PluginTask
+ plugin.PluginModel
+ plugin.PluginMigration
+ plugin.PluginBlueprintV100
+ plugin.DataSourcePluginBlueprintV200
+ plugin.CloseablePluginTask
+ plugin.PluginSource
+} = (*Bamboo)(nil)
+
+type Bamboo struct{}
+
+func (p Bamboo) Init(br context.BasicRes) errors.Error {
+ api.Init(br)
+ return nil
+}
+
+func (p Bamboo) Connection() interface{} {
+ return &models.BambooConnection{}
+}
+
+func (p Bamboo) Scope() interface{} {
+ return nil
+}
+
+func (p Bamboo) TransformationRule() interface{} {
+ return nil
+}
+
+func (p Bamboo) MakeDataSourcePipelinePlanV200(connectionId uint64, scopes []*plugin.BlueprintScopeV200, syncPolicy plugin.BlueprintSyncPolicy) (plugin.PipelinePlan, []plugin.Scope, errors.Error) {
+ //return api.MakePipelinePlanV200(p.SubTaskMetas(), connectionId, scopes, &syncPolicy)
+ return nil, nil, nil
+}
+
+func (p Bamboo) GetTablesInfo() []dal.Tabler {
+ return []dal.Tabler{
+ &models.BambooConnection{},
+ }
+}
+
+func (p Bamboo) Description() string {
+ return "collect some Bamboo data"
+}
+
+func (p Bamboo) SubTaskMetas() []plugin.SubTaskMeta {
+ // TODO add your sub task here
+ return []plugin.SubTaskMeta{}
+}
+
+func (p Bamboo) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]interface{}) (interface{}, errors.Error) {
+ op, err := tasks.DecodeAndValidateTaskOptions(options)
+ if err != nil {
+ return nil, err
+ }
+ connectionHelper := helper.NewConnectionHelper(
+ taskCtx,
+ nil,
+ )
+ connection := &models.BambooConnection{}
+ err = connectionHelper.FirstById(connection, op.ConnectionId)
+ if err != nil {
+ return nil, errors.Default.Wrap(err, "unable to get Bamboo connection by the given connection ID")
+ }
+
+ apiClient, err := tasks.NewBambooApiClient(taskCtx, connection)
+ if err != nil {
+ return nil, errors.Default.Wrap(err, "unable to get Bamboo API client instance")
+ }
+
+ return &tasks.BambooTaskData{
+ Options: op,
+ ApiClient: apiClient,
+ }, nil
+}
+
+// PkgPath information lost when compiled as plugin(.so)
+func (p Bamboo) RootPkgPath() string {
+ return "github.com/apache/incubator-devlake/plugins/bamboo"
+}
+
+func (p Bamboo) MigrationScripts() []plugin.MigrationScript {
+ return migrationscripts.All()
+}
+
+func (p Bamboo) ApiResources() map[string]map[string]plugin.ApiResourceHandler {
+ return map[string]map[string]plugin.ApiResourceHandler{
+ "test": {
+ "POST": api.TestConnection,
+ },
+ "connections": {
+ "POST": api.PostConnections,
+ "GET": api.ListConnections,
+ },
+ "connections/:connectionId": {
+ "GET": api.GetConnection,
+ "PATCH": api.PatchConnection,
+ "DELETE": api.DeleteConnection,
+ },
+ }
+}
+
+func (p Bamboo) MakePipelinePlan(connectionId uint64, scope []*plugin.BlueprintScopeV100) (plugin.PipelinePlan, errors.Error) {
+ //return api.MakePipelinePlan(p.SubTaskMetas(), connectionId, scope)
+ return nil, nil
+}
+
+func (p Bamboo) Close(taskCtx plugin.TaskContext) errors.Error {
+ data, ok := taskCtx.GetData().(*tasks.BambooTaskData)
+ if !ok {
+ return errors.Default.New(fmt.Sprintf("GetData failed when try to close %+v", taskCtx))
+ }
+ data.ApiClient.Release()
+ return nil
+}
diff --git a/backend/plugins/bamboo/models/connection.go b/backend/plugins/bamboo/models/connection.go
new file mode 100644
index 000000000..88520d463
--- /dev/null
+++ b/backend/plugins/bamboo/models/connection.go
@@ -0,0 +1,128 @@
+/*
+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 models
+
+import (
+ "encoding/xml"
+ "fmt"
+ "net/http"
+
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
+)
+
+type BambooConnection struct {
+ api.BaseConnection `mapstructure:",squash"`
+ BambooConn `mapstructure:",squash"`
+}
+
+// TODO Please modify the following code to fit your needs
+// This object conforms to what the frontend currently sends.
+type BambooConn struct {
+ api.RestConnection `mapstructure:",squash"`
+ //TODO you may need to use helper.BasicAuth instead of helper.AccessToken
+ api.AccessToken `mapstructure:",squash"`
+}
+
+// PrepareApiClient test api and set the IsPrivateToken,version,UserId and so on.
+func (conn *BambooConn) PrepareApiClient(apiClient apihelperabstract.ApiClientAbstract) errors.Error {
+ header := http.Header{}
+ header.Set("Authorization", fmt.Sprintf("Bearer %v", conn.Token))
+
+ res, err := apiClient.Get("", nil, header)
+ if err != nil {
+ return errors.HttpStatus(400).New(fmt.Sprintf("Get failed %s", err.Error()))
+ }
+ resources := &ApiXMLResourcesResponse{}
+
+ if res.StatusCode != http.StatusOK {
+ return errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code: %d", res.StatusCode))
+ }
+
+ err = api.UnmarshalResponseXML(res, resources)
+
+ if err != nil {
+ return errors.HttpStatus(500).New(fmt.Sprintf("UnmarshalResponse failed %s", err.Error()))
+ }
+
+ if resources.Link.Href != conn.Endpoint {
+ return errors.HttpStatus(400).New(fmt.Sprintf("Response Data error for connection endpoint: %s, it should like: http://{domain}/rest/api/latest/", conn.Endpoint))
+ }
+
+ res, err = apiClient.Get("repository", nil, header)
+ if err != nil {
+ return errors.HttpStatus(400).New(fmt.Sprintf("Get failed %s", err.Error()))
+ }
+ repo := &ApiRepository{}
+
+ if res.StatusCode != http.StatusOK {
+ return errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code: %d", res.StatusCode))
+ }
+
+ err = api.UnmarshalResponse(res, repo)
+
+ if err != nil {
+ return errors.HttpStatus(400).New(fmt.Sprintf("UnmarshalResponse repository failed %s", err.Error()))
+ }
+
+ return nil
+}
+
+// This object conforms to what the frontend currently expects.
+type BambooResponse struct {
+ Name string `json:"name"`
+ ID int `json:"id"`
+ BambooConnection
+}
+
+type ApiRepository struct {
+ Size int `json:"size"`
+ SearchResults interface{} `json:"searchResults"`
+ StartIndex int `json:"start-index"`
+ MaxResult int `json:"max-result"`
+}
+
+type ApiXMLLink struct {
+ XMLName xml.Name `json:"xml_name" xml:"link"`
+ Href string `json:"href" xml:"href,attr"`
+}
+
+type ApiXMLResource struct {
+ XMLName xml.Name `json:"xml_name" xml:"resource"`
+ Name string `json:"name" xml:"name,attr"`
+}
+
+type ApiXMLResources struct {
+ XMLName xml.Name `json:"xml_name" xml:"resources"`
+ Size string `json:"size" xml:"size,attr"`
+ Resources []ApiXMLResource `json:"resource" xml:"resource"`
+}
+
+// Using User because it requires authentication.
+type ApiXMLResourcesResponse struct {
+ XMLName xml.Name `json:"xml_name" xml:"resources"`
+ Expand string `json:"expand" xml:"expand,attr"`
+
+ Link ApiXMLLink `json:"link" xml:"link"`
+ Resources ApiXMLResources `json:"resources" xml:"resources"`
+}
+
+func (BambooConnection) TableName() string {
+ return "_tool_bamboo_connections"
+}
diff --git a/backend/plugins/bamboo/models/migrationscripts/20230216_add_init_tables.go b/backend/plugins/bamboo/models/migrationscripts/20230216_add_init_tables.go
new file mode 100644
index 000000000..d43bd53b3
--- /dev/null
+++ b/backend/plugins/bamboo/models/migrationscripts/20230216_add_init_tables.go
@@ -0,0 +1,42 @@
+/*
+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 migrationscripts
+
+import (
+ "github.com/apache/incubator-devlake/core/context"
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/helpers/migrationhelper"
+ "github.com/apache/incubator-devlake/plugins/bamboo/models/migrationscripts/archived"
+)
+
+type addInitTables struct{}
+
+func (u *addInitTables) Up(baseRes context.BasicRes) errors.Error {
+ return migrationhelper.AutoMigrateTables(
+ baseRes,
+ archived.BambooConnection{},
+ )
+}
+
+func (*addInitTables) Version() uint64 {
+ return 20230216205024
+}
+
+func (*addInitTables) Name() string {
+ return "bamboo init schemas"
+}
diff --git a/backend/plugins/bamboo/models/migrationscripts/archived/connection.go b/backend/plugins/bamboo/models/migrationscripts/archived/connection.go
new file mode 100644
index 000000000..e99545ebe
--- /dev/null
+++ b/backend/plugins/bamboo/models/migrationscripts/archived/connection.go
@@ -0,0 +1,77 @@
+/*
+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 archived
+
+import "time"
+
+type Model struct {
+ ID uint64 `gorm:"primaryKey" json:"id"`
+ CreatedAt time.Time `json:"createdAt"`
+ UpdatedAt time.Time `json:"updatedAt"`
+}
+type BaseConnection struct {
+ Name string `gorm:"type:varchar(100);uniqueIndex" json:"name" validate:"required"`
+ Model
+}
+
+// RestConnection implements the ApiConnection interface
+type RestConnection struct {
+ Endpoint string `mapstructure:"endpoint" validate:"required" json:"endpoint"`
+ Proxy string `mapstructure:"proxy" json:"proxy"`
+ RateLimitPerHour int `comment:"api request rate limit per hour" json:"rateLimitPerHour"`
+}
+
+// AccessToken FIXME ...
+type AccessToken struct {
+ Token string `mapstructure:"token" validate:"required" json:"token" encrypt:"yes"`
+}
+
+type BambooConn struct {
+ RestConnection `mapstructure:",squash"`
+ //TODO you may need to use helper.BasicAuth instead of helper.AccessToken
+ AccessToken `mapstructure:",squash"`
+}
+
+// TODO Please modify the following code to fit your needs
+// This object conforms to what the frontend currently sends.
+type BambooConnection struct {
+ BaseConnection `mapstructure:",squash"`
+ BambooConn `mapstructure:",squash"`
+}
+
+type TestConnectionRequest struct {
+ Endpoint string `json:"endpoint"`
+ Proxy string `json:"proxy"`
+ AccessToken `mapstructure:",squash"`
+}
+
+// This object conforms to what the frontend currently expects.
+type BambooResponse struct {
+ Name string `json:"name"`
+ ID int `json:"id"`
+ BambooConnection
+}
+
+// Using User because it requires authentication.
+type ApiResourcesResponse struct {
+ Resources string `json:"resources" xml:"resources"`
+}
+
+func (BambooConnection) TableName() string {
+ return "_tool_bamboo_connections"
+}
diff --git a/backend/plugins/bamboo/models/migrationscripts/register.go b/backend/plugins/bamboo/models/migrationscripts/register.go
new file mode 100644
index 000000000..ec054748c
--- /dev/null
+++ b/backend/plugins/bamboo/models/migrationscripts/register.go
@@ -0,0 +1,29 @@
+/*
+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 migrationscripts
+
+import (
+ "github.com/apache/incubator-devlake/core/plugin"
+)
+
+// All return all the migration scripts
+func All() []plugin.MigrationScript {
+ return []plugin.MigrationScript{
+ new(addInitTables),
+ }
+}
diff --git a/backend/plugins/bamboo/tasks/api_client.go b/backend/plugins/bamboo/tasks/api_client.go
new file mode 100644
index 000000000..6efbb21a5
--- /dev/null
+++ b/backend/plugins/bamboo/tasks/api_client.go
@@ -0,0 +1,72 @@
+/*
+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 (
+ "net/http"
+ "strconv"
+ "time"
+
+ "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/bamboo/models"
+)
+
+func CreateBambooAsyncApiClient(
+ taskCtx plugin.TaskContext,
+ apiClient *api.ApiClient,
+ connection *models.BambooConnection,
+) (*api.ApiAsyncClient, errors.Error) {
+ // create rate limit calculator
+ rateLimiter := &api.ApiRateLimitCalculator{
+ UserRateLimitPerHour: connection.RateLimitPerHour,
+ DynamicRateLimit: func(res *http.Response) (int, time.Duration, errors.Error) {
+ rateLimitHeader := res.Header.Get("RateLimit-Limit")
+ if rateLimitHeader == "" {
+ // use default
+ return 0, 0, nil
+ }
+ rateLimit, err := strconv.Atoi(rateLimitHeader)
+ if err != nil {
+ return 0, 0, errors.Default.Wrap(err, "failed to parse RateLimit-Limit header")
+ }
+ // seems like {{ .plugin-ame }} rate limit is on minute basis
+ return rateLimit, 1 * time.Minute, nil
+ },
+ }
+ asyncApiClient, err := api.CreateAsyncApiClient(
+ taskCtx,
+ apiClient,
+ rateLimiter,
+ )
+ if err != nil {
+ return nil, err
+ }
+ return asyncApiClient, nil
+}
+
+func NewBambooApiClient(taskCtx plugin.TaskContext, connection *models.BambooConnection) (*api.ApiAsyncClient, errors.Error) {
+ // create synchronize api client so we can calculate api rate limit dynamically
+ apiClient, err := api.NewApiClientFromConnection(taskCtx.GetContext(), taskCtx, connection)
+ if err != nil {
+ return nil, err
+ }
+
+ return CreateBambooAsyncApiClient(taskCtx, apiClient, connection)
+}
diff --git a/backend/plugins/bamboo/tasks/task_data.go b/backend/plugins/bamboo/tasks/task_data.go
new file mode 100644
index 000000000..ea5c62bce
--- /dev/null
+++ b/backend/plugins/bamboo/tasks/task_data.go
@@ -0,0 +1,52 @@
+/*
+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 (
+ "github.com/apache/incubator-devlake/core/errors"
+ helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+)
+
+type BambooApiParams struct {
+}
+
+type BambooOptions struct {
+ // TODO add some custom options here if necessary
+ // options means some custom params required by plugin running.
+ // Such As How many rows do your want
+ // You can use it in sub tasks and you need pass it in main.go and pipelines.
+ ConnectionId uint64 `json:"connectionId"`
+ Tasks []string `json:"tasks,omitempty"`
+ Since string
+}
+
+type BambooTaskData struct {
+ Options *BambooOptions
+ ApiClient *helper.ApiAsyncClient
+}
+
+func DecodeAndValidateTaskOptions(options map[string]interface{}) (*BambooOptions, errors.Error) {
+ var op 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
+}