Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: add subtask register for github plugin #5411

Merged
merged 31 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e330df5
refactor: add subtask registert for github
chenggui53 Jun 23, 2023
de798ad
refactor: add subtask register
chenggui53 Jun 23, 2023
73ecee5
refactor: add subtask register
chenggui53 Jun 23, 2023
47c8191
refactor: add subtask register
chenggui53 Jun 26, 2023
e71c802
refactor: add subtask register
chenggui53 Jun 26, 2023
9f4c593
refactor: add subtask register
chenggui53 Jun 26, 2023
d0c793a
refactor: add subtask register
chenggui53 Jun 26, 2023
9c9c676
refactor: add subtask register
chenggui53 Jun 27, 2023
5f1568e
refactor: add subtask register
chenggui53 Jun 27, 2023
ba0c96f
refactor: add subtask register
chenggui53 Jun 27, 2023
1d2f614
refactor: add subtask register
chenggui53 Jun 27, 2023
044943d
refactor: add subtask register
chenggui53 Jun 28, 2023
2422bb5
refactor: add subtask register
chenggui53 Jun 28, 2023
5d6b670
refactor: add subtask register
chenggui53 Jun 30, 2023
9a462c0
refactor: add subtask register
chenggui53 Jul 3, 2023
6788fca
refactor: add subtask register
chenggui53 Jul 3, 2023
e9e4c33
refactor: add subtask meta register
chenggui53 Jul 4, 2023
675a9ea
refactor: add subtask register
chenggui53 Jul 9, 2023
c77cc19
refactor: add subtask register
chenggui53 Jul 9, 2023
eff7c22
refactor: add subtask register
chenggui53 Jul 9, 2023
9c40e0a
refactor: Update remote.go
chenggui53 Jul 11, 2023
21f6206
refactor: add subtask register
chenggui53 Jul 12, 2023
f51b4a2
refactor: add subtask register
chenggui53 Jul 12, 2023
e489477
refactor: add subtask register
chenggui53 Jul 12, 2023
658ce99
refactor: add subtask register
chenggui53 Jul 12, 2023
bc460a9
refactor: add subtask register
chenggui53 Jul 12, 2023
10c7fe7
refactor: update subtask register
chenggui53 Jul 13, 2023
844d80f
refactor: update subtask register
chenggui53 Jul 13, 2023
e98293e
refactor: add subtask register
chenggui53 Jul 19, 2023
54aee04
refactor: add subtask register
chenggui53 Jul 19, 2023
416fcbd
refactor: add subtask register
chenggui53 Jul 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/core/plugin/plugin_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package plugin

import (
"context"

corecontext "github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/errors"
)
Expand Down Expand Up @@ -98,6 +99,8 @@ type SubTaskMeta struct {
Description string
DomainTypes []string
Dependencies []*SubTaskMeta
DependencyTables []string
ProductTables []string
}

// PluginTask Implement this interface to let framework run tasks for you
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type ApiCollectorStateManager struct {
ExecuteStart time.Time
}

// NewApiCollectorWithState create a new ApiCollectorStateManager
// NewStatefulApiCollector create a new ApiCollectorStateManager
func NewStatefulApiCollector(args RawDataSubTaskArgs, timeAfter *time.Time) (*ApiCollectorStateManager, errors.Error) {
db := args.Ctx.GetDal()

Expand Down
2 changes: 1 addition & 1 deletion backend/helpers/pluginhelper/api/batch_save.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/apache/incubator-devlake/core/log"
)

// BatchSave performs mulitple records persistence of a specific type in one sql query to improve the performance
// BatchSave performs multiple records persistence of a specific type in one sql query to improve the performance
type BatchSave struct {
basicRes context.BasicRes
log log.Logger
Expand Down
3 changes: 1 addition & 2 deletions backend/helpers/pluginhelper/api/connection_auths.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ import (
"reflect"
"strings"

"github.com/apache/incubator-devlake/core/plugin"

"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/go-playground/validator/v10"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package subtaskmeta_sorter
package sorter

import "github.com/apache/incubator-devlake/core/plugin"
import (
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
)

type SubTaskMetaSorter interface {
Sort() ([]plugin.SubTaskMeta, error)
Sort() ([]plugin.SubTaskMeta, errors.Error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package subtaskmeta_sorter
package sorter

import (
"fmt"

"github.com/apache/incubator-devlake/core/errors"

"github.com/apache/incubator-devlake/core/plugin"
"sort"
)

type DependencySorter struct {
Expand All @@ -31,12 +33,12 @@ func NewDependencySorter(metas []*plugin.SubTaskMeta) SubTaskMetaSorter {
return &DependencySorter{metas: metas}
}

func (d *DependencySorter) Sort() ([]plugin.SubTaskMeta, error) {
return topologicalSort(d.metas)
func (d *DependencySorter) Sort() ([]plugin.SubTaskMeta, errors.Error) {
return dependenciesTopologicalSort(d.metas)
}

// stable topological sort
func topologicalSort(metas []*plugin.SubTaskMeta) ([]plugin.SubTaskMeta, error) {
func dependenciesTopologicalSort(metas []*plugin.SubTaskMeta) ([]plugin.SubTaskMeta, errors.Error) {
// which state will make a cycle
dependenciesMap := make(map[string][]string)
nameMetaMap := make(map[string]*plugin.SubTaskMeta)
Expand All @@ -56,63 +58,25 @@ func topologicalSort(metas []*plugin.SubTaskMeta) ([]plugin.SubTaskMeta, error)
dependenciesMap[item.Name] = make([]string, 0)
}
} else {
return nil, fmt.Errorf("duplicate subtaskmetas detected in list: %s", item.Name)
return nil, errors.Convert(fmt.Errorf("duplicate subtaskmetas detected in list: %s", item.Name))
}
}

orderedSubtaskList := make([]plugin.SubTaskMeta, 0)
for {
if len(dependenciesMap) == 0 {
break
}

tmpList := make([]string, 0)
for key, item := range dependenciesMap {
if len(item) == 0 {
tmpList = append(tmpList, key)
}
}
if len(tmpList) == 0 {
return nil, fmt.Errorf("cyclic dependency detected: %v", dependenciesMap)
}

// remove item in dependencies map
for key, value := range dependenciesMap {
if contains(tmpList, key) {
delete(dependenciesMap, key)
} else {
dependenciesMap[key] = removeElements(value, tmpList)
}
}

sort.Strings(tmpList)
// convert item to subtaskmeta by name, and append to orderedSubtaskList
for _, item := range tmpList {
value, ok := nameMetaMap[item]
if !ok {
return nil, fmt.Errorf("illeagal subtaskmeta detected %s", item)
}
orderedSubtaskList = append(orderedSubtaskList, *value)
}
// sort
orderStrList, err := topologicalSortSameElements(dependenciesMap)
if err != nil {
return nil, errors.Convert(err)
}
return orderedSubtaskList, nil
}

func contains[T comparable](itemList []T, item T) bool {
for _, newItem := range itemList {
if item == newItem {
return true
// gen list by sorted name list and return
orderedSubtaskList := make([]plugin.SubTaskMeta, 0)
for _, item := range orderStrList {
value, ok := nameMetaMap[item]
if !ok {
return nil, errors.Convert(fmt.Errorf("illeagal subtaskmeta detected %s", item))
}
orderedSubtaskList = append(orderedSubtaskList, *value)
}
return false
}

func removeElements[T comparable](raw, toRemove []T) []T {
newList := make([]T, 0)
for _, item := range raw {
if !contains(toRemove, item) {
newList = append(newList, item)
}
}
return newList
return orderedSubtaskList, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package subtaskmeta_sorter
package sorter

import (
"github.com/apache/incubator-devlake/core/plugin"
"reflect"
"testing"

"github.com/apache/incubator-devlake/core/plugin"
)

func Test_topologicalSort(t *testing.T) {
Expand Down Expand Up @@ -85,13 +86,13 @@ func Test_topologicalSort(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := topologicalSort(tt.args.metas)
got, err := dependenciesTopologicalSort(tt.args.metas)
if (err != nil) != tt.wantErr {
t.Errorf("topologicalSort() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("dependenciesTopologicalSort() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("topologicalSort() got = %v, want %v", got, tt.want)
t.Errorf("dependenciesTopologicalSort() got = %v, want %v", got, tt.want)
}
})
}
Expand Down
80 changes: 80 additions & 0 deletions backend/helpers/pluginhelper/subtaskmeta/sorter/table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
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 sorter

import (
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
)

type TableSorter struct {
metas []*plugin.SubTaskMeta
}

func NewTableSorter(metas []*plugin.SubTaskMeta) SubTaskMetaSorter {
return &TableSorter{metas: metas}
}

func (d *TableSorter) Sort() ([]plugin.SubTaskMeta, errors.Error) {
return tableTopologicalSort(d.metas)
}

func tableTopologicalSort(metas []*plugin.SubTaskMeta) ([]plugin.SubTaskMeta, errors.Error) {
constructedMetas := constructDependenciesByTable(metas)
return dependenciesTopologicalSort(constructedMetas)
}

func constructDependenciesByTable(metas []*plugin.SubTaskMeta) []*plugin.SubTaskMeta {
chenggui53 marked this conversation as resolved.
Show resolved Hide resolved
// construct map by metas and their produced tables, the key is table, and value is metas
tableMetasMap := make(map[string][]*plugin.SubTaskMeta)
for _, item := range metas {
for _, tableItem := range item.ProductTables {
if value, ok := tableMetasMap[tableItem]; ok {
tableMetasMap[tableItem] = append(value, item)
} else {
tableMetasMap[tableItem] = []*plugin.SubTaskMeta{item}
}
}
}
// construct meta dependencies by meta.TableDependencies
// use noDupMap to deduplicate dependencies of meta
noDupMap := make(map[*plugin.SubTaskMeta]map[*plugin.SubTaskMeta]any)
for _, metaItem := range metas {
// convert dependency tables to dependency metas
dependenciesMap, ok := noDupMap[metaItem]
if !ok {
noDupMap[metaItem] = make(map[*plugin.SubTaskMeta]any)
dependenciesMap = noDupMap[metaItem]
}
for _, tableItem := range metaItem.DependencyTables {
chenggui53 marked this conversation as resolved.
Show resolved Hide resolved
for _, item := range tableMetasMap[tableItem] {
dependenciesMap[item] = ""
}
}
metaItem.Dependencies = keys(dependenciesMap)
}
return metas
}

func keys[T comparable](raw map[T]any) []T {
list := make([]T, 0)
for key := range raw {
list = append(list, key)
}
return list
}
81 changes: 81 additions & 0 deletions backend/helpers/pluginhelper/subtaskmeta/sorter/table_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
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 sorter

import (
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"reflect"
"testing"
)

func Test_tableTopologicalSort(t *testing.T) {
pluginA := plugin.SubTaskMeta{
Name: "A",
DependencyTables: []string{},
ProductTables: []string{"_TOOL_TEST_TABLE", "_TOOL_TEST_TABLE2"},
}
pluginB := plugin.SubTaskMeta{
Name: "B",
DependencyTables: []string{"_TOOL_TEST_TABLE"},
ProductTables: []string{"_TOOL_TEST_TABLE2", "_TOOL_TEST_TABLE3"},
}
pluginC := plugin.SubTaskMeta{
Name: "C",
DependencyTables: []string{"_TOOL_TEST_TABLE"},
ProductTables: []string{"_TOOL_TEST_TABLE3"},
}
pluginD := plugin.SubTaskMeta{
Name: "D",
DependencyTables: []string{"_TOOL_TEST_TABLE2", "_TOOL_TEST_TABLE3"},
ProductTables: []string{"_TOOL_TEST_TABLE4"},
}

type args struct {
metas []*plugin.SubTaskMeta
}
tests := []struct {
name string
args args
want []plugin.SubTaskMeta
want1 errors.Error
}{
{
name: "test sorter",
args: args{[]*plugin.SubTaskMeta{&pluginA, &pluginB, &pluginC, &pluginD}},
want: []plugin.SubTaskMeta{pluginA, pluginB, pluginC, pluginD},
want1: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := tableTopologicalSort(tt.args.metas)
if len(got) != len(tt.want) {
t.Errorf("tableTopologicalSort() got = %v, want %v", got, tt.want)
}
for index, item := range got {
if item.Name != tt.want[index].Name {
t.Errorf("tableTopologicalSort() got = %v, want %v, not equal with index = %d", got, tt.want, index)
}
}
if !reflect.DeepEqual(got1, tt.want1) {
t.Errorf("tableTopologicalSort() got1 = %v, want %v", got1, tt.want1)
}
})
}
}
Loading
Loading