Skip to content

Commit 7924eae

Browse files
committed
core/config/docs: config enhancements
1 parent 5931d35 commit 7924eae

30 files changed

Lines changed: 76 additions & 514 deletions

core/cmd/node_commands_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestShell_IndexEVMNodes(t *testing.T) {
9898

9999
func solanaStartNewApplication(t *testing.T, cfgs ...*solcfg.TOMLConfig) *cltest.TestApplication {
100100
for i := range cfgs {
101-
cfgs[i].Chain.SetDefaults()
101+
cfgs[i].SetDefaults()
102102
}
103103
return startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) {
104104
c.Solana = cfgs

core/config/docs/chains-evm.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# EVM defaults depend on ChainID:
22
#
3-
# **EXTENDED**
43
[[EVM]]
54
# ChainID is the EVM chain ID. Mandatory.
65
ChainID = '1' # Example

core/config/docs/cmd/generate/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"flag"
77
"fmt"
88
"os"
9-
"path"
9+
"path/filepath"
1010

1111
"github.com/smartcontractkit/chainlink/v2/core/config/docs"
1212
)
@@ -26,11 +26,11 @@ func main() {
2626
fmt.Fprintf(os.Stderr, "invalid secrets docs: %v\n", err)
2727
os.Exit(1)
2828
}
29-
if err = os.WriteFile(path.Join(*outDir, "CONFIG.md"), []byte(c), 0600); err != nil {
29+
if err = os.WriteFile(filepath.Join(*outDir, "CONFIG.md"), []byte(c), 0600); err != nil {
3030
fmt.Fprintf(os.Stderr, "failed to write config docs: %v\n", err)
3131
os.Exit(1)
3232
}
33-
if err = os.WriteFile(path.Join(*outDir, "SECRETS.md"), []byte(s), 0600); err != nil {
33+
if err = os.WriteFile(filepath.Join(*outDir, "SECRETS.md"), []byte(s), 0600); err != nil {
3434
fmt.Fprintf(os.Stderr, "failed to write secrets docs: %v\n", err)
3535
os.Exit(1)
3636
}

core/config/docs/defaults.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import (
55
"strings"
66

77
"github.com/smartcontractkit/chainlink-common/pkg/config"
8+
"github.com/smartcontractkit/chainlink-common/pkg/config/configtest"
89
pgcommon "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg"
910

1011
"github.com/smartcontractkit/chainlink/v2/core/config/toml"
11-
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest"
1212
)
1313

1414
var (
1515
defaults toml.Core
1616
)
1717

1818
func init() {
19-
if err := cfgtest.DocDefaultsOnly(strings.NewReader(coreTOML), &defaults, config.DecodeTOML); err != nil {
19+
if err := configtest.DocDefaultsOnly(strings.NewReader(coreTOML), &defaults, config.DecodeTOML); err != nil {
2020
log.Fatalf("Failed to initialize defaults from docs: %v", err)
2121
}
2222
}

core/config/docs/defaults_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ package docs
33
import (
44
"testing"
55

6-
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest"
6+
"github.com/smartcontractkit/chainlink-common/pkg/config/configtest"
77
)
88

99
func TestCoreDefaults_notNil(t *testing.T) {
10-
cfgtest.AssertFieldsNotNil(t, CoreDefaults())
10+
configtest.AssertFieldsNotNil(t, CoreDefaults())
1111
}

core/config/docs/docs.go

Lines changed: 9 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,9 @@ package docs
22

33
import (
44
_ "embed"
5-
"errors"
65
"fmt"
7-
"log"
8-
"strings"
96

10-
"github.com/smartcontractkit/chainlink-common/pkg/config"
11-
)
12-
13-
const (
14-
fieldDefault = "# Default"
15-
fieldExample = "# Example"
16-
17-
tokenAdvanced = "**ADVANCED**"
18-
tokenExtended = "**EXTENDED**"
7+
"github.com/smartcontractkit/chainlink-common/pkg/config/configdoc"
198
)
209

2110
var (
@@ -42,233 +31,26 @@ var (
4231

4332
// GenerateConfig returns MarkDown documentation generated from core.toml & chains-*.toml.
4433
func GenerateConfig() (string, error) {
45-
return generateDocs(docsTOML, `[//]: # (Documentation generated from docs/*.toml - DO NOT EDIT.)
34+
evmDefaults, err := evmChainDefaults()
35+
if err != nil {
36+
return "", fmt.Errorf("failed to generate evm chain defaults: %w", err)
37+
}
38+
return configdoc.Generate(docsTOML, `[//]: # (Documentation generated from docs/*.toml - DO NOT EDIT.)
4639
4740
This document describes the TOML format for configuration.
4841
4942
See also [SECRETS.md](SECRETS.md)
50-
`, exampleConfig)
43+
`, exampleConfig, map[string]string{"EVM": evmDefaults})
5144
}
5245

5346
// GenerateSecrets returns MarkDown documentation generated from secrets.toml.
5447
func GenerateSecrets() (string, error) {
55-
return generateDocs(secretsTOML, `[//]: # (Documentation generated from docs/secrets.toml - DO NOT EDIT.)
48+
return configdoc.Generate(secretsTOML, `[//]: # (Documentation generated from docs/secrets.toml - DO NOT EDIT.)
5649
5750
This document describes the TOML format for secrets.
5851
5952
Each secret has an alternative corresponding environment variable.
6053
6154
See also [CONFIG.md](CONFIG.md)
62-
`, exampleSecrets)
63-
}
64-
65-
// generateDocs returns MarkDown documentation generated from the TOML string.
66-
func generateDocs(toml, header, example string) (string, error) {
67-
items, err := parseTOMLDocs(toml)
68-
var sb strings.Builder
69-
70-
sb.WriteString(header)
71-
sb.WriteString(`
72-
## Example
73-
74-
`)
75-
sb.WriteString("```toml\n")
76-
sb.WriteString(example)
77-
sb.WriteString("```\n\n")
78-
79-
for _, item := range items {
80-
sb.WriteString(item.String())
81-
sb.WriteString("\n\n")
82-
}
83-
84-
return sb.String(), err
85-
}
86-
87-
func advancedWarning(msg string) string {
88-
return fmt.Sprintf(":warning: **_ADVANCED_**: _%s_\n", msg)
89-
}
90-
91-
// lines holds a set of contiguous lines
92-
type lines []string
93-
94-
func (d lines) String() string {
95-
return strings.Join(d, "\n")
96-
}
97-
98-
type table struct {
99-
name string
100-
codes lines
101-
adv bool
102-
desc lines
103-
ext bool
104-
}
105-
106-
func newTable(line string, desc lines) *table {
107-
t := &table{
108-
name: strings.Trim(line, "[]"),
109-
codes: []string{line},
110-
desc: desc,
111-
}
112-
if len(desc) > 0 {
113-
if strings.HasPrefix(strings.TrimSpace(desc[0]), tokenAdvanced) {
114-
t.adv = true
115-
t.desc = t.desc[1:]
116-
} else if strings.HasPrefix(strings.TrimSpace(desc[len(desc)-1]), tokenExtended) {
117-
t.ext = true
118-
t.desc = t.desc[:len(desc)-1]
119-
}
120-
}
121-
return t
122-
}
123-
124-
func newArrayOfTables(line string, desc lines) *table {
125-
t := &table{
126-
name: strings.Trim(strings.Trim(line, fieldExample), "[]"),
127-
codes: []string{line},
128-
desc: desc,
129-
}
130-
if len(desc) > 0 {
131-
if strings.HasPrefix(strings.TrimSpace(desc[0]), tokenAdvanced) {
132-
t.adv = true
133-
t.desc = t.desc[1:]
134-
} else if strings.HasPrefix(strings.TrimSpace(desc[len(desc)-1]), tokenExtended) {
135-
t.ext = true
136-
t.desc = t.desc[:len(desc)-1]
137-
}
138-
}
139-
return t
140-
}
141-
142-
func (t table) advanced() string {
143-
if t.adv {
144-
return advancedWarning("Do not change these settings unless you know what you are doing.")
145-
}
146-
return ""
147-
}
148-
149-
func (t table) code() string {
150-
if !t.ext {
151-
return fmt.Sprint("```toml\n", t.codes, "\n```\n")
152-
}
153-
return ""
154-
}
155-
156-
func (t table) extended() string {
157-
if t.ext {
158-
if t.name != "EVM" {
159-
log.Fatalf("%s: no extended description available", t.name)
160-
}
161-
s, err := evmChainDefaults()
162-
if err != nil {
163-
log.Fatalf("%s: failed to generate evm chain defaults: %v", t.name, err)
164-
}
165-
return s
166-
}
167-
return ""
168-
}
169-
170-
// String prints a table as an H2, followed by a code block and description.
171-
func (t *table) String() string {
172-
return fmt.Sprint("## ", t.name, "\n",
173-
t.advanced(),
174-
t.code(),
175-
t.desc,
176-
t.extended())
177-
}
178-
179-
type keyval struct {
180-
name string
181-
code string
182-
adv bool
183-
desc lines
184-
}
185-
186-
func newKeyval(line string, desc lines) keyval {
187-
line = strings.TrimSpace(line)
188-
kv := keyval{
189-
name: line[:strings.Index(line, " ")],
190-
code: line,
191-
desc: desc,
192-
}
193-
if len(desc) > 0 && strings.HasPrefix(strings.TrimSpace(desc[0]), tokenAdvanced) {
194-
kv.adv = true
195-
kv.desc = kv.desc[1:]
196-
}
197-
return kv
198-
}
199-
200-
func (k keyval) advanced() string {
201-
if k.adv {
202-
return advancedWarning("Do not change this setting unless you know what you are doing.")
203-
}
204-
return ""
205-
}
206-
207-
// String prints a keyval as an H3, followed by a code block and description.
208-
func (k keyval) String() string {
209-
name := k.name
210-
if i := strings.LastIndex(name, "."); i > -1 {
211-
name = name[i+1:]
212-
}
213-
return fmt.Sprint("### ", name, "\n",
214-
k.advanced(),
215-
"```toml\n",
216-
k.code,
217-
"\n```\n",
218-
k.desc)
219-
}
220-
221-
func parseTOMLDocs(s string) (items []fmt.Stringer, err error) {
222-
defer func() { _, err = config.MultiErrorList(err) }()
223-
globalTable := table{name: "Global"}
224-
currentTable := &globalTable
225-
items = append(items, currentTable)
226-
var desc lines
227-
for _, line := range strings.Split(s, "\n") {
228-
if strings.HasPrefix(line, "#") {
229-
// comment
230-
desc = append(desc, strings.TrimSpace(line[1:]))
231-
} else if strings.TrimSpace(line) == "" {
232-
// empty
233-
if len(desc) > 0 {
234-
items = append(items, desc)
235-
desc = nil
236-
}
237-
} else if strings.HasPrefix(line, "[[") {
238-
currentTable = newArrayOfTables(line, desc)
239-
items = append(items, currentTable)
240-
desc = nil
241-
} else if strings.HasPrefix(line, "[") {
242-
currentTable = newTable(line, desc)
243-
items = append(items, currentTable)
244-
desc = nil
245-
} else {
246-
kv := newKeyval(line, desc)
247-
shortName := kv.name
248-
if currentTable != &globalTable {
249-
// update to full name
250-
kv.name = currentTable.name + "." + kv.name
251-
}
252-
if len(kv.desc) == 0 {
253-
err = errors.Join(err, fmt.Errorf("%s: missing description", kv.name))
254-
} else if !strings.HasPrefix(kv.desc[0], shortName) {
255-
err = errors.Join(err, fmt.Errorf("%s: description does not begin with %q", kv.name, shortName))
256-
}
257-
if !strings.HasSuffix(line, fieldDefault) && !strings.HasSuffix(line, fieldExample) {
258-
err = errors.Join(err, fmt.Errorf(`%s: is not one of %v`, kv.name, []string{fieldDefault, fieldExample}))
259-
}
260-
261-
items = append(items, kv)
262-
currentTable.codes = append(currentTable.codes, kv.code)
263-
desc = nil
264-
}
265-
}
266-
if len(globalTable.codes) == 0 {
267-
// drop it
268-
items = items[1:]
269-
}
270-
if len(desc) > 0 {
271-
items = append(items, desc)
272-
}
273-
return
55+
`, exampleSecrets, nil)
27456
}

core/config/docs/docs_test.go

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import (
66

77
"github.com/kylelemons/godebug/diff"
88
gotoml "github.com/pelletier/go-toml/v2"
9-
pkgerrors "github.com/pkg/errors"
109
"github.com/stretchr/testify/assert"
1110
"github.com/stretchr/testify/require"
1211

1312
"github.com/smartcontractkit/chainlink-common/pkg/config"
13+
"github.com/smartcontractkit/chainlink-common/pkg/config/configtest"
1414
solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
1515

1616
"github.com/smartcontractkit/chainlink-evm/pkg/assets"
@@ -19,27 +19,13 @@ import (
1919
"github.com/smartcontractkit/chainlink-evm/pkg/types"
2020
"github.com/smartcontractkit/chainlink/v2/core/config/docs"
2121
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
22-
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest"
2322
)
2423

2524
func TestDoc(t *testing.T) {
26-
d := gotoml.NewDecoder(strings.NewReader(docs.DocsTOML))
27-
d.DisallowUnknownFields() // Ensure no extra fields
28-
var c chainlink.Config
29-
err := d.Decode(&c)
30-
var strict *gotoml.StrictMissingError
31-
if err != nil && strings.Contains(err.Error(), "undecoded keys: ") {
32-
t.Errorf("Docs contain extra fields: %v", err)
33-
} else if pkgerrors.As(err, &strict) {
34-
t.Fatal("StrictMissingError:", strict.String())
35-
} else {
36-
require.NoError(t, err)
37-
}
38-
39-
cfgtest.AssertFieldsNotNil(t, c)
25+
configtest.AssertDocsTOMLComplete[chainlink.Config](t, docs.DocsTOML)
4026

4127
var defaults chainlink.Config
42-
require.NoError(t, cfgtest.DocDefaultsOnly(strings.NewReader(docs.DocsTOML), &defaults, config.DecodeTOML))
28+
require.NoError(t, configtest.DocDefaultsOnly(strings.NewReader(docs.DocsTOML), &defaults, config.DecodeTOML))
4329

4430
t.Run("EVM", func(t *testing.T) {
4531
fallbackDefaults := toml.Defaults(nil)

core/config/docs/example-config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ ChainID = '1' # Required
66
[[EVM.Nodes]]
77
Name = 'fake' # Required
88
WSURL = 'wss://foo.bar/ws'
9-
HTTPURL = 'https://foo.bar' # Required
9+
HTTPURL = 'https://foo.bar' # Required

core/config/docs/example-secrets.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
URL = 'postgresql://user:pass@localhost:5432/dbname?sslmode=disable' # Required
33

44
[Password]
5-
Keystore = 'keystore_pass' # Required
5+
Keystore = 'keystore_pass' # Required

0 commit comments

Comments
 (0)