Skip to content

Commit c5161ac

Browse files
committed
core/config/docs: config enhancements
1 parent e0d8a61 commit c5161ac

26 files changed

Lines changed: 75 additions & 317 deletions

File tree

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: 10 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,8 @@ package docs
33
import (
44
_ "embed"
55
"fmt"
6-
"log"
7-
"strings"
86

9-
"go.uber.org/multierr"
10-
11-
"github.com/smartcontractkit/chainlink-common/pkg/config"
12-
)
13-
14-
const (
15-
fieldDefault = "# Default"
16-
fieldExample = "# Example"
17-
18-
tokenAdvanced = "**ADVANCED**"
19-
tokenExtended = "**EXTENDED**"
7+
"github.com/smartcontractkit/chainlink-common/pkg/config/configdoc"
208
)
219

2210
var (
@@ -26,6 +14,7 @@ var (
2614
coreTOML string
2715
//go:embed chains-evm.toml
2816
chainsEVMTOML string
17+
//TODO link to repo instead?
2918
//go:embed chains-cosmos.toml
3019
chainsCosmosTOML string
3120
//go:embed chains-solana.toml
@@ -43,233 +32,26 @@ var (
4332

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

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

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)