Skip to content

Commit 4635fef

Browse files
committed
refactor: use regex for config extract
Signed-off-by: Meng JiaFeng <[email protected]>
1 parent c42f7c2 commit 4635fef

File tree

15 files changed

+475
-312
lines changed

15 files changed

+475
-312
lines changed

internal/pkg/configmanager/app.go

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package configmanager
33
import (
44
"fmt"
55

6-
"gopkg.in/yaml.v3"
7-
8-
"github.com/devstream-io/devstream/pkg/util/file"
6+
"github.com/devstream-io/devstream/pkg/util/log"
97
"github.com/devstream-io/devstream/pkg/util/scm"
108
)
119

@@ -27,29 +25,27 @@ type app struct {
2725
CDRawConfigs []pipelineRaw `yaml:"cd" mapstructure:"cd"`
2826
}
2927

30-
func getAppsFromConfigFileWithVarsRendered(fileBytes []byte, vars map[string]any) ([]*app, error) {
31-
yamlPath := "$.apps[*]"
32-
yamlStrArray, err := file.GetYamlNodeArrayByPath(fileBytes, yamlPath)
28+
func (a *app) getTools(vars map[string]any, templateMap map[string]string) (Tools, error) {
29+
// generate app repo and template repo from scmInfo
30+
a.setDefault()
31+
repoScaffoldingTool, err := a.getRepoTemplateTool()
3332
if err != nil {
34-
return nil, err
35-
}
36-
37-
if yamlStrArray == nil {
38-
return make([]*app, 0), nil
33+
return nil, fmt.Errorf("app[%s] can't get valid repo config: %w", a.Name, err)
3934
}
4035

41-
yamlWithVars, err := renderConfigWithVariables(yamlStrArray.StrOrigin, vars)
36+
// get ci/cd pipelineTemplates
37+
appVars := a.Spec.merge(vars)
38+
tools, err := a.generateCICDToolsFromAppConfig(templateMap, appVars)
4239
if err != nil {
43-
return nil, err
40+
return nil, fmt.Errorf("app[%s] get pipeline tools failed: %w", a.Name, err)
4441
}
45-
46-
var retTApps = make([]*app, 0)
47-
err = yaml.Unmarshal(yamlWithVars, &retTApps)
48-
if err != nil {
49-
return nil, err
42+
if repoScaffoldingTool != nil {
43+
tools = append(tools, repoScaffoldingTool)
5044
}
5145

52-
return retTApps, nil
46+
log.Debugf("Have got %d tools from app %s.", len(tools), a.Name)
47+
48+
return tools, nil
5349
}
5450

5551
// getAppPipelineTool generate ci/cd tools from app config
Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,56 @@
11
package configmanager
22

33
import (
4+
"fmt"
5+
46
. "github.com/onsi/ginkgo/v2"
57
. "github.com/onsi/gomega"
8+
9+
"github.com/devstream-io/devstream/pkg/util/scm"
610
)
711

8-
var _ = Describe("getToolsFromConfigFileWithVarsRendered", func() {
9-
const appsConfig = `---
10-
apps:
11-
- name: app-1
12-
cd:
13-
- type: template
14-
vars:
15-
app: [[ appName ]]
16-
`
17-
When("get apps from config file", func() {
18-
It("should return config with vars", func() {
19-
apps, err := getAppsFromConfigFileWithVarsRendered([]byte(appsConfig), map[string]any{"appName": interface{}("app-1")})
20-
Expect(err).NotTo(HaveOccurred())
21-
Expect(apps).NotTo(BeNil())
22-
Expect(len(apps)).To(Equal(1))
23-
Expect(len(apps[0].CDRawConfigs)).To(Equal(1))
24-
Expect(apps[0].CDRawConfigs[0].Vars["app"]).To(Equal(interface{}("app-1")))
12+
var _ = Describe("app struct", func() {
13+
var (
14+
a *app
15+
appName string
16+
vars map[string]any
17+
templateMap map[string]string
18+
)
19+
BeforeEach(func() {
20+
appName = "test_app"
21+
vars = map[string]any{}
22+
templateMap = map[string]string{}
23+
})
24+
Context("getTools method", func() {
25+
When("repo is not valid", func() {
26+
BeforeEach(func() {
27+
a = &app{Name: appName}
28+
})
29+
It("should return error", func() {
30+
_, err := a.getTools(vars, templateMap)
31+
Expect(err).Should(HaveOccurred())
32+
Expect(err.Error()).Should(ContainSubstring(fmt.Sprintf("app[%s] can't get valid repo config", appName)))
33+
})
34+
})
35+
When("ci/cd template is not valid", func() {
36+
BeforeEach(func() {
37+
a = &app{
38+
Repo: &scm.SCMInfo{
39+
CloneURL: "http://test.com/test/test_app",
40+
},
41+
CIRawConfigs: []pipelineRaw{
42+
{
43+
Type: "template",
44+
TemplateName: "not_exist",
45+
},
46+
},
47+
}
48+
})
49+
It("should return error", func() {
50+
_, err := a.getTools(vars, templateMap)
51+
Expect(err).Should(HaveOccurred())
52+
Expect(err.Error()).Should(ContainSubstring("not found in pipelineTemplates"))
53+
})
2554
})
2655
})
2756
})

internal/pkg/configmanager/config.go

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,65 +4,13 @@ import (
44
"fmt"
55

66
"gopkg.in/yaml.v3"
7-
8-
"github.com/devstream-io/devstream/pkg/util/log"
97
)
108

119
// Config is a general config in DevStream.
1210
type Config struct {
1311
Config CoreConfig `yaml:"config"`
1412
Vars map[string]any `yaml:"vars"`
1513
Tools Tools `yaml:"tools"`
16-
Apps []*app `yaml:"apps"`
17-
// We'll read the pipeline templates from config file and render it to pipelineTemplateMap in no time.
18-
//PipelineTemplates []*pipelineTemplate `yaml:"-"`
19-
pipelineTemplateMap map[string]string `yaml:"-"`
20-
}
21-
22-
func (c *Config) getToolsFromApps() (Tools, error) {
23-
var tools Tools
24-
for _, a := range c.Apps {
25-
appTools, err := c.getToolsFromApp(a)
26-
if err != nil {
27-
return nil, err
28-
}
29-
tools = append(tools, appTools...)
30-
}
31-
return tools, nil
32-
}
33-
34-
func (c *Config) getToolsFromApp(a *app) (Tools, error) {
35-
// generate app repo and template repo from scmInfo
36-
a.setDefault()
37-
repoScaffoldingTool, err := a.getRepoTemplateTool()
38-
if err != nil {
39-
return nil, fmt.Errorf("app[%s] get repo failed: %w", a.Name, err)
40-
}
41-
42-
// get ci/cd pipelineTemplates
43-
appVars := a.Spec.merge(c.Vars)
44-
tools, err := a.generateCICDToolsFromAppConfig(c.pipelineTemplateMap, appVars)
45-
if err != nil {
46-
return nil, fmt.Errorf("app[%s] get pipeline tools failed: %w", a.Name, err)
47-
}
48-
if repoScaffoldingTool != nil {
49-
tools = append(tools, repoScaffoldingTool)
50-
}
51-
52-
// all tools from apps should depend on the original tools,
53-
// because dtm will execute all original tools first, then execute all tools from apps
54-
for _, toolFromApps := range tools {
55-
for _, t := range c.Tools {
56-
toolFromApps.DependsOn = append(toolFromApps.DependsOn, t.KeyWithNameAndInstanceID())
57-
}
58-
}
59-
60-
log.Debugf("Have got %d tools from app %s.", len(tools), a.Name)
61-
for i, t := range tools {
62-
log.Debugf("Tool %d: %v", i+1, t)
63-
}
64-
65-
return tools, nil
6614
}
6715

6816
func (c *Config) renderInstanceIDtoOptions() {

internal/pkg/configmanager/configmanager.go

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,17 @@ func NewManager(configFilePath string) *Manager {
2020
// LoadConfig is the only method that the caller of Manager needs to be concerned with, and this method returns a *Config finally.
2121
// The main workflow of this method is:
2222
// 1. Get the original config from the config file specified by ConfigFilePath;
23-
// 2. Parsing tools from the apps, and merge that tools to Config.Tools;
24-
// 3. Validation.
23+
// 2. Validation.
2524
func (m *Manager) LoadConfig() (*Config, error) {
26-
// step 1
25+
// step 1: get config
2726
c, err := m.getConfigFromFileWithGlobalVars()
2827
if err != nil {
2928
return nil, err
3029
}
31-
32-
// step 2
33-
appTools, err := c.getToolsFromApps()
34-
if err != nil {
35-
return nil, err
36-
}
37-
38-
c.Tools = append(c.Tools, appTools...)
30+
// set instanceID in options
3931
c.renderInstanceIDtoOptions()
4032

41-
// step 3
33+
// step 2: check config is valid
4234
if err = c.validate(); err != nil {
4335
return nil, err
4436
}
@@ -50,50 +42,50 @@ func (m *Manager) LoadConfig() (*Config, error) {
5042
// 1. render the global variables to Config.Tools and Config.Apps
5143
// 2. transfer the PipelineTemplates to Config.pipelineTemplateMap, it's map[string]string type.
5244
// We can't render the original config file to Config.PipelineTemplates directly for the:
53-
// 1. variables rendered must be before the yaml.Unmarshal() called for the [[ foo ]] will be treated as a two-dimensional array by the yaml parser;
54-
// 2. the variables used([[ foo ]]) in the Config.PipelineTemplates can be defined in the Config.Apps or Config.Vars;
55-
// 3. pipeline templates are used in apps, so it would be more appropriate to refer to pipeline templates when dealing with apps
45+
// 1. variables rendered must be before the yaml.Unmarshal() called for the [[ foo ]] will be treated as a two-dimensional array by the yaml parser;
46+
// 2. the variables used([[ foo ]]) in the Config.PipelineTemplates can be defined in the Config.Apps or Config.Vars;
5647
func (m *Manager) getConfigFromFileWithGlobalVars() (*Config, error) {
5748
configBytes, err := os.ReadFile(m.ConfigFilePath)
5849
if err != nil {
5950
return nil, err
6051
}
6152

62-
// global variables
63-
vars, err := getVarsFromConfigFile(configBytes)
53+
// extract top raw config struct from config text
54+
r, err := newRawConfigFromConfigBytes(configBytes)
55+
if err != nil {
56+
return nil, err
57+
}
58+
// 1. get global variables
59+
vars, err := r.getVars()
6460
if err != nil {
6561
return nil, fmt.Errorf("failed to get variables from config file. Error: %w", err)
6662
}
6763

68-
// tools with global variables rendered
69-
tools, err := getToolsFromConfigFileWithVarsRendered(configBytes, vars)
64+
// 2. tools with global variables rendered
65+
tools, err := r.getToolsWithVars(vars)
7066
if err != nil {
7167
return nil, fmt.Errorf("failed to get tools from config file. Error: %w", err)
7268
}
7369

74-
// apps with global variables rendered
75-
apps, err := getAppsFromConfigFileWithVarsRendered(configBytes, vars)
70+
// 3. apps tools with global variables rendered
71+
appTools, err := r.getAppToolsWithVars(vars)
7672
if err != nil {
7773
return nil, fmt.Errorf("failed to get apps from config file. Error: %w", err)
7874
}
75+
// all tools from apps should depend on the original tools,
76+
// because dtm will execute all original tools first, then execute all tools from apps
77+
appTools.updateToolDepends(tools)
78+
tools = append(tools, appTools...)
7979

80-
// pipelineTemplateMap transfer from PipelineTemplates
81-
pipelineTemplateMap, err := getPipelineTemplatesMapFromConfigFile(configBytes)
82-
if err != nil {
83-
return nil, fmt.Errorf("failed to get pipelineTemplatesMap from config file. Error: %w", err)
84-
}
85-
86-
// coreConfig without any changes
87-
coreConfig, err := getCoreConfigFromConfigFile(configBytes)
80+
// 4. coreConfig without any changes
81+
coreConfig, err := r.getConfig()
8882
if err != nil {
8983
return nil, fmt.Errorf("failed to get coreConfig from config file. Error: %w", err)
9084
}
9185

9286
return &Config{
93-
Config: *coreConfig,
94-
Vars: vars,
95-
Tools: tools,
96-
Apps: apps,
97-
pipelineTemplateMap: pipelineTemplateMap,
87+
Config: *coreConfig,
88+
Vars: vars,
89+
Tools: tools,
9890
}, nil
9991
}

internal/pkg/configmanager/configmanager_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ var _ = Describe("LoadConfig", func() {
218218
})
219219

220220
When("load a config file", func() {
221-
It("should return 5 tools", func() {
221+
It("should return tools", func() {
222222
mgr := NewManager(filepath.Join(tmpWorkDir, "config.yaml"))
223223
cfg, err := mgr.LoadConfig()
224224
Expect(err).NotTo(HaveOccurred())
@@ -274,9 +274,7 @@ var _ = Describe("getConfigFromFileWithGlobalVars", func() {
274274
Expect(err).NotTo(HaveOccurred())
275275
Expect(cfg.Config.State.Backend).To(Equal("local"))
276276
Expect(cfg.Vars["foo1"]).To(Equal("bar1"))
277-
Expect(len(cfg.Apps)).To(Equal(1))
278-
Expect(cfg.Apps[0].Name).To(Equal("service-a"))
279-
Expect(len(cfg.Tools)).To(Equal(2))
277+
Expect(len(cfg.Tools)).To(Equal(5))
280278
Expect(cfg.Tools[1].Name).To(Equal("plugin2"))
281279
})
282280
})
Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
package configmanager
22

3-
import (
4-
"gopkg.in/yaml.v3"
5-
6-
"github.com/devstream-io/devstream/pkg/util/file"
7-
)
8-
93
type CoreConfig struct {
104
State *State `yaml:"state"`
115
}
@@ -29,18 +23,3 @@ type StateConfigOptions struct {
2923
Namespace string `yaml:"namespace"`
3024
ConfigMap string `yaml:"configmap"`
3125
}
32-
33-
func getCoreConfigFromConfigFile(fileBytes []byte) (*CoreConfig, error) {
34-
yamlPath := "$.config"
35-
yamlStr, err := file.GetYamlNodeStrByPath(fileBytes, yamlPath)
36-
if err != nil {
37-
return nil, err
38-
}
39-
40-
var config *CoreConfig
41-
err = yaml.Unmarshal([]byte(yamlStr), &config)
42-
if err != nil {
43-
return nil, err
44-
}
45-
return config, nil
46-
}

internal/pkg/configmanager/coreconfig_test.go

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)