Skip to content

Commit 5a1a3c9

Browse files
committed
fix: add unit tests and fix bugs
1 parent 58e1445 commit 5a1a3c9

File tree

14 files changed

+370
-35
lines changed

14 files changed

+370
-35
lines changed

docs/plugins/trello-github-integ_plugin.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## 1 `trello-github-integ` Plugin
22

3-
This plugin creates a new GitHub Actions file(trello-github-integration) and upload to your GitHub repo.
3+
This plugin creates a new GitHub Actions workflow(trello-github-integration) and uploads it to your GitHub repo.
44

55
## 2 Usage:
66

@@ -17,18 +17,18 @@ tools:
1717
# checkout the version from the GitHub releases
1818
version: 0.2.0
1919
# optional; if specified, dtm will make sure the dependency is applied first before handling this tool.
20-
dependsOn: [ "TOOL1_NAME.TOOL1_KIND", "TOOL2_NAME.TOOL2_KIND" ]
20+
dependsOn: [ "TRELLO_INSTANCE_NAME.trello" ]
2121
# options for the plugin
2222
options:
2323
# the repo's owner. It should be case-sensitive here; strictly use your GitHub user name; please change the value below.
2424
owner: YOUR_GITHUB_USERNAME
2525
# the repo where you'd like to setup GitHub Actions; please change the value below.
2626
repo: YOUR_REPO_NAME
2727
# reference parameters come from dependency, their usage will be explained later
28-
boardId: ${{ default.trello.outputs.boardId }}
29-
todoListId: ${{ default.trello.outputs.todoListId }}
30-
doingListId: ${{ default.trello.outputs.doingListId }}
31-
doneListId: ${{ default.trello.outputs.doneListId }}
28+
boardId: ${{ TRELLO_INSTANCE_NAME.trello.outputs.boardId }}
29+
todoListId: ${{ TRELLO_INSTANCE_NAME.trello.outputs.todoListId }}
30+
doingListId: ${{ TRELLO_INSTANCE_NAME.trello.outputs.doingListId }}
31+
doneListId: ${{ TRELLO_INSTANCE_NAME.trello.outputs.doneListId }}
3232
# main branch of the repo (to which branch the plugin will submit the workflows)
3333
branch: main
3434
```
@@ -67,8 +67,8 @@ tools:
6767

6868
In the example above:
6969

70-
- We put `default.trello` as dependency by using the `dependsOn` keyword.
71-
- We use `default.trello`'s output as input for the `default_trello_github` plugin.
70+
- We put `trello_init_demo.trello` as a dependency by using the `dependsOn` keyword.
71+
- We use `trello_init_demo.trello`'s output as input for the `trello_github_integ_demo` plugin.
7272

7373
Pay attention to the `${{ xxx }}` part in the example. `${{ TOOL_NAME.TOOL_KIND.outputs.var}}` is the syntax for using an output.
7474

docs/plugins/trello_plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ tools:
6969

7070
In the example above:
7171

72-
- We put `default.trello` as dependency by using the `dependsOn` keyword.
72+
- We put `default.trello` as a dependency by using the `dependsOn` keyword.
7373
- We use `default.trello`'s output as input for the `default_trello_github` plugin.
7474

7575
Pay attention to the `${{ xxx }}` part in the example. `${{ TOOL_NAME.TOOL_KIND.outputs.var}}` is the syntax for using an output.

internal/pkg/plugin/trello/helper.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ func buildReadState(options *Options) (map[string]interface{}, error) {
3737
return nil, err
3838
}
3939

40+
output := make(map[string]interface{})
41+
output["boardId"] = fmt.Sprint(listIds["boardId"])
42+
output["todoListId"] = fmt.Sprint(listIds["todoListId"])
43+
output["doingListId"] = fmt.Sprint(listIds["doingListId"])
44+
output["doneListId"] = fmt.Sprint(listIds["doneListId"])
45+
46+
listIds["outputs"] = output
4047
return listIds, nil
4148
}
4249

internal/pkg/plugin/trello/trello.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ func CreateTrelloBoard(options *Options) (*TrelloItemId, error) {
2828
return nil, err
2929
}
3030

31+
exist, err := c.CheckBoardExists(options.Owner, options.Repo, options.KanbanBoardName)
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
if exist {
37+
log.Infof("Board already exists, owner: %s, repo: %s, kanbanName: %s.", options.Owner, options.Repo, options.KanbanBoardName)
38+
listIds, err := c.GetBoardIdAndListId(options.Owner, options.Repo, options.KanbanBoardName)
39+
if err != nil {
40+
return nil, err
41+
}
42+
return &TrelloItemId{
43+
boardId: fmt.Sprint(listIds["boardId"]),
44+
todoListId: fmt.Sprint(listIds["todoListId"]),
45+
doingListId: fmt.Sprint(listIds["doingListId"]),
46+
doneListId: fmt.Sprint(listIds["doneListId"]),
47+
}, nil
48+
}
49+
3150
board, err := c.CreateBoard(options.KanbanBoardName, options.Owner, options.Repo)
3251
if err != nil {
3352
return nil, err

internal/pkg/plugin/trellogithub/create.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@ func Create(options map[string]interface{}) (map[string]interface{}, error) {
1717

1818
log.Success("Adding workflow file succeeded.")
1919

20-
trelloIds := &TrelloItemId{
20+
trelloItemId := &TrelloItemId{
2121
boardId: tg.options.BoardId,
2222
todoListId: tg.options.todoListId,
2323
doingListId: tg.options.doingListId,
2424
doneListId: tg.options.doneListId,
2525
}
2626

27-
if err := tg.AddTrelloIdSecret(trelloIds); err != nil {
27+
if err := tg.AddTrelloIdSecret(trelloItemId); err != nil {
2828
return nil, err
2929
}
3030

3131
log.Success("Adding secret keys for trello succeeded.")
3232

33-
return buildState(tg, trelloIds), nil
33+
return buildState(tg), nil
3434
}

internal/pkg/plugin/trellogithub/helper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"fmt"
55
)
66

7-
func buildState(tg *TrelloGithub, ti *TrelloItemId) map[string]interface{} {
7+
func buildState(tg *TrelloGithub) map[string]interface{} {
88
res := make(map[string]interface{})
99
res["workflowDir"] = fmt.Sprintf("/repos/%s/%s/contents/.github/workflows", tg.options.Owner, tg.options.Repo)
1010
return res

internal/pkg/plugin/trellogithub/update.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@ func Update(options map[string]interface{}) (map[string]interface{}, error) {
2323

2424
log.Success("Adding workflow file succeeded.")
2525

26-
trelloIds := &TrelloItemId{
26+
trelloItemId := &TrelloItemId{
2727
boardId: tg.options.BoardId,
2828
todoListId: tg.options.todoListId,
2929
doingListId: tg.options.doingListId,
3030
doneListId: tg.options.doneListId,
3131
}
3232

33-
if err := tg.AddTrelloIdSecret(trelloIds); err != nil {
33+
if err := tg.AddTrelloIdSecret(trelloItemId); err != nil {
3434
return nil, err
3535
}
3636
log.Success("Adding secret keys for trello succeeded.")
3737

38-
return buildState(tg, trelloIds), nil
38+
return buildState(tg), nil
3939
}

internal/pkg/pluginengine/change.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ import (
1414
const REF_PREFIX = "${{"
1515
const REF_SUFFIX = "}}"
1616

17+
// eg. ${{name.kind.outputs.key}},name setgment number is 0
18+
const NAME_SEGMENT_NUM = 0
19+
20+
// eg. ${{name.kind.outputs.key}},kind setgment number is 1
21+
const KIND_SEGMENT_NUM = 1
22+
23+
// eg. ${{name.kind.outputs.key}},key setgment number is 3
24+
const REF_SEGMENT_NUM = 3
25+
1726
// Change is a wrapper with a single Tool and its Action should be execute.
1827
type Change struct {
1928
Tool *configloader.Tool
@@ -101,13 +110,13 @@ func execute(smgr statemanager.Manager, changes []*Change) map[string]error {
101110
var err error
102111
var returnValue map[string]interface{}
103112

104-
log.Info("tool raw changes: ", c.Tool.Options)
113+
log.Infof("Tool's raw changes are: %s.", c.Tool.Options)
105114
// fill ref inputs
106115
err = fillRefValueWithOutputs(smgr, c.Tool.Options)
107116
if err != nil {
108117
succeeded = false
109118
}
110-
log.Info("tool changes with filled inputs: ", c.Tool.Options)
119+
log.Infof("Tool's changes with filled inputs are: %s.", c.Tool.Options)
111120

112121
switch c.ActionName {
113122
case statemanager.ActionCreate:
@@ -183,34 +192,35 @@ func handleResult(smgr statemanager.Manager, change *Change) error {
183192
return nil
184193
}
185194

186-
// FillInputParams fill inputs from state
195+
// fillRefValueWithOutputs fill inputs from state
187196
func fillRefValueWithOutputs(smgr statemanager.Manager, options map[string]interface{}) error {
188-
// traverse options
189197
for key, value := range options {
190198
log.Debugf("Key: %s, Value: %s.", key, value)
191199
// judge whether the value is a string
192200
if inst, ok := value.(string); ok {
193201
// judge whether the format is ${{xxx}}
194-
if strings.HasPrefix(inst, REF_PREFIX) && strings.HasSuffix(inst, REF_SUFFIX) {
195-
ref := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(inst, REF_PREFIX), REF_SUFFIX))
202+
if isValidRefFormat(inst) {
203+
ref := getRefFormatString(inst)
196204
log.Debug("Ref inputs: ", ref)
197205
refParam := strings.Split(ref, ".")
198206
if len(refParam) <= 3 {
199-
return errors.New("ref input format is not correct: " + ref)
207+
return errors.New("incorrect output reference: " + ref)
200208
}
201209

202-
outputs, err := smgr.GetOutputs(statemanager.GenStateKey(refParam))
210+
outputs, err := smgr.GetOutputs(statemanager.GenStateKey(refParam[NAME_SEGMENT_NUM], refParam[KIND_SEGMENT_NUM]))
203211
if err != nil {
204212
return err
205213
}
206214
log.Debug("Ref outputs: ", outputs)
207215

208216
if outs, ok := outputs.(map[string]interface{}); ok {
209217
log.Debug("Ref outs: ", outs)
210-
log.Debug("Ref param: ", refParam[3])
211-
options[key] = outs[refParam[3]]
218+
log.Debug("Ref param: ", refParam[REF_SEGMENT_NUM])
212219
if value == nil {
213-
return errors.New("ref input value is null: " + refParam[3])
220+
return errors.New("ref input value is null: " + refParam[REF_SEGMENT_NUM])
221+
}
222+
if options[key], ok = outs[refParam[REF_SEGMENT_NUM]]; !ok {
223+
return fmt.Errorf("can not find %s in dependency outputs", refParam[REF_SEGMENT_NUM])
214224
}
215225
}
216226
}
@@ -224,3 +234,13 @@ func fillRefValueWithOutputs(smgr statemanager.Manager, options map[string]inter
224234
}
225235
return nil
226236
}
237+
238+
// isValidRefFormat if the format is ${{abc}}
239+
func isValidRefFormat(ref string) bool {
240+
return strings.HasPrefix(ref, REF_PREFIX) && strings.HasSuffix(ref, REF_SUFFIX)
241+
}
242+
243+
// getRefFormatString get abc from ${{abc}} or ${{ abc }}
244+
func getRefFormatString(rawFormatString string) string {
245+
return strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(rawFormatString, REF_PREFIX), REF_SUFFIX))
246+
}

internal/pkg/pluginengine/change_helper.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ func changesForApply(smgr statemanager.Manager, cfg *configloader.Config) ([]*Ch
8282
description := fmt.Sprintf("Tool < %s > found in config but doesn't exist in the state, will be created.", tool.Name)
8383
changes = append(changes, generateCreateAction(&tool, description))
8484
} else {
85+
if err := renderRefByDependency(&tool, cfg.Tools, smgr); err != nil {
86+
return nil, err
87+
}
8588
// tool found in the state
8689
if drifted(tool.Options, state.Options) {
8790
// tool's config differs from State's, Update
@@ -166,3 +169,33 @@ func changesForForceDelete(smgr statemanager.Manager, cfg *configloader.Config)
166169
}
167170
return changes
168171
}
172+
173+
// renderRefByDependency
174+
// 1. if dependency plugin changed, do not fill ${{***}} with ref value;
175+
// 2. if dependency plugin did not change, fill ${{***}} with ref value;
176+
func renderRefByDependency(tool *configloader.Tool, tools []configloader.Tool, smgr statemanager.Manager) error {
177+
if len(tool.DependsOn) > 0 {
178+
for _, dependency := range tool.DependsOn {
179+
dependencyChange := false
180+
for _, c := range tools {
181+
log.Debugf("====== Name: %s kind: %s dependency: %s =====", c.Name, c.Plugin.Kind, dependency)
182+
if fmt.Sprintf("%s%s%s", c.Name, ".", c.Plugin.Kind) == dependency {
183+
state := smgr.GetState(statemanager.StateKeyGenerateFunc(&c))
184+
if drifted(c.Options, state.Options) {
185+
dependencyChange = true
186+
}
187+
}
188+
}
189+
if !dependencyChange {
190+
// fill ref inputs,
191+
if err := fillRefValueWithOutputs(smgr, tool.Options); err != nil {
192+
return err
193+
}
194+
log.Infof("Dependency plugin no changes, ref inputs will be filled: %s.", tool.Options)
195+
} else {
196+
log.Infof("Do not fill ref inputs now, they will be filled when dependency plugin complete: %s.", tool.Options)
197+
}
198+
}
199+
}
200+
return nil
201+
}

0 commit comments

Comments
 (0)