Skip to content

Commit e6de26e

Browse files
Remove stdout option as default and implement base logging (#61)
* upgrade to go 1.21 * throw error when method or path not found in OAS * add slog warning for circular references * upgrade spec and add validate warning * update version/validate for spec * remove stdout as default option for output * hook up logging plumbing * add top level logging * warn * add docs for config package * add explorer docs * doc strings * comment cleanup * Update internal/cmd/generate.go Co-authored-by: Benjamin Bennett <[email protected]> * Update internal/config/parse.go Co-authored-by: Benjamin Bennett <[email protected]> * update doc links --------- Co-authored-by: Benjamin Bennett <[email protected]>
1 parent 4c61112 commit e6de26e

34 files changed

+407
-253
lines changed

Makefile

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@ generate:
1717
# Regenerate testdata folder
1818
testdata:
1919
go run ./cmd/tfplugingen-openapi generate \
20-
--config ./internal/cmd/testdata/petstore3/tfopenapigen_config.yml \
21-
./internal/cmd/testdata/petstore3/openapi_spec.json \
22-
> ./internal/cmd/testdata/petstore3/generated_framework_ir.json
20+
--config ./internal/cmd/testdata/petstore3/generator_config.yml \
21+
--output ./internal/cmd/testdata/petstore3/provider_code_spec.json \
22+
./internal/cmd/testdata/petstore3/openapi_spec.json
2323

2424
go run ./cmd/tfplugingen-openapi generate \
25-
--config ./internal/cmd/testdata/github/tfopenapigen_config.yml \
26-
./internal/cmd/testdata/github/openapi_spec.json \
27-
> ./internal/cmd/testdata/github/generated_framework_ir.json
25+
--config ./internal/cmd/testdata/github/generator_config.yml \
26+
--output ./internal/cmd/testdata/github/provider_code_spec.json \
27+
./internal/cmd/testdata/github/openapi_spec.json
2828

2929
go run ./cmd/tfplugingen-openapi generate \
30-
--config ./internal/cmd/testdata/scaleway/tfopenapigen_config.yml \
31-
./internal/cmd/testdata/scaleway/openapi_spec.yml \
32-
> ./internal/cmd/testdata/scaleway/generated_framework_ir.json
30+
--config ./internal/cmd/testdata/scaleway/generator_config.yml \
31+
--output ./internal/cmd/testdata/scaleway/provider_code_spec.json \
32+
./internal/cmd/testdata/scaleway/openapi_spec.yml
3333

3434
go run ./cmd/tfplugingen-openapi generate \
35-
--config ./internal/cmd/testdata/edgecase/tfopenapigen_config.yml \
36-
./internal/cmd/testdata/edgecase/openapi_spec.yml \
37-
> ./internal/cmd/testdata/edgecase/generated_framework_ir.json
35+
--config ./internal/cmd/testdata/edgecase/generator_config.yml \
36+
--output ./internal/cmd/testdata/edgecase/provider_code_spec.json \
37+
./internal/cmd/testdata/edgecase/openapi_spec.yml
3838

3939
.PHONY: lint fmt test

go.mod

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
module github.com/hashicorp/terraform-plugin-codegen-openapi
22

3-
go 1.20
3+
go 1.21
44

55
require (
66
github.com/google/go-cmp v0.5.9
7-
github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230804072831-c6dffebf6781
7+
github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230927170433-b779baa44f04
88
github.com/mattn/go-colorable v0.1.13
99
github.com/mitchellh/cli v1.1.5
10-
github.com/pb33f/libopenapi v0.9.2
10+
github.com/pb33f/libopenapi v0.11.0
1111
gopkg.in/yaml.v3 v3.0.1
1212
)
1313

@@ -35,6 +35,7 @@ require (
3535
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
3636
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
3737
golang.org/x/crypto v0.7.0 // indirect
38+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
3839
golang.org/x/sync v0.3.0 // indirect
39-
golang.org/x/sys v0.7.0 // indirect
40+
golang.org/x/sys v0.12.0 // indirect
4041
)

go.sum

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
2424
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
2525
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
2626
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
27+
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
2728
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
2829
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
2930
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -54,8 +55,8 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
5455
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
5556
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
5657
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
57-
github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230804072831-c6dffebf6781 h1:FvNFHIsSf/5Yd5DTsLXoMhKVx6pRdCdkwvEt/SmbUWg=
58-
github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230804072831-c6dffebf6781/go.mod h1:4aZFKiOI2xiQFOpeQMMyDL8vRmKAZXHUY4kWol7Fdco=
58+
github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230927170433-b779baa44f04 h1:WrMQeSAMqgVEqqBvqL0hSBYy2uk2qn9YtwlFgn1vRjk=
59+
github.com/hashicorp/terraform-plugin-codegen-spec v0.0.0-20230927170433-b779baa44f04/go.mod h1:4aZFKiOI2xiQFOpeQMMyDL8vRmKAZXHUY4kWol7Fdco=
5960
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
6061
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
6162
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@@ -68,9 +69,11 @@ github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
6869
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
6970
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
7071
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
72+
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
7173
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
7274
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
7375
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
76+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
7477
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
7578
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
7679
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@@ -101,14 +104,15 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
101104
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
102105
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
103106
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
104-
github.com/pb33f/libopenapi v0.9.2 h1:QFxTgTSmW9mnXhQ+myignBh19ZPkFRxnAvbPnFcesDs=
105-
github.com/pb33f/libopenapi v0.9.2/go.mod h1:lvUmCtjgHUGVj6WzN3I5/CS9wkXtyN3Ykjh6ZZP5lrI=
107+
github.com/pb33f/libopenapi v0.11.0 h1:xhFWajHaTVXD5+hh7LHY7kVBDVEVMSO509NFs6SOiu4=
108+
github.com/pb33f/libopenapi v0.11.0/go.mod h1:s8uj6S0DjWrwZVj20ianJBz+MMjHAbeeRYNyo9ird74=
106109
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
107110
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
108111
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
109112
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
110113
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
111114
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
115+
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
112116
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
113117
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
114118
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -124,6 +128,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
124128
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
125129
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
126130
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
131+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
127132
github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
128133
github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
129134
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
@@ -143,6 +148,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
143148
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
144149
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
145150
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
151+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
152+
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
146153
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
147154
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
148155
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -156,6 +163,7 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
156163
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
157164
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
158165
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
166+
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
159167
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
160168
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
161169
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -181,8 +189,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
181189
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
182190
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
183191
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
184-
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
185-
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
192+
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
193+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
186194
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
187195
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
188196
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -192,6 +200,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
192200
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
193201
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
194202
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
203+
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
195204
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
196205
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
197206
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=

internal/cmd/generate.go

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
package cmd
55

66
import (
7+
"context"
78
"encoding/json"
89
"errors"
910
"flag"
1011
"fmt"
11-
"log"
12+
"log/slog"
1213
"os"
1314
"strings"
1415

@@ -19,6 +20,7 @@ import (
1920

2021
"github.com/mitchellh/cli"
2122
"github.com/pb33f/libopenapi"
23+
"github.com/pb33f/libopenapi/resolver"
2224
)
2325

2426
type GenerateCommand struct {
@@ -30,8 +32,8 @@ type GenerateCommand struct {
3032

3133
func (cmd *GenerateCommand) Flags() *flag.FlagSet {
3234
fs := flag.NewFlagSet("generate", flag.ExitOnError)
33-
fs.StringVar(&cmd.flagConfigPath, "config", "./tfopenapigen_config.yml", "path to config file (YAML)")
34-
fs.StringVar(&cmd.flagOutputPath, "output", "", "path to output generated Framework IR file (JSON)")
35+
fs.StringVar(&cmd.flagConfigPath, "config", "./generator_config.yml", "path to generator config file (YAML)")
36+
fs.StringVar(&cmd.flagOutputPath, "output", "./provider_code_spec.json", "destination file path for generated provider code spec (JSON)")
3537
return fs
3638
}
3739

@@ -74,137 +76,153 @@ func (cmd *GenerateCommand) Help() string {
7476
}
7577

7678
func (cmd *GenerateCommand) Synopsis() string {
77-
return "Generates Framework Intermediate Representation (IR) JSON for an OpenAPI spec (JSON or YAML format)"
79+
return "Generates Provider Code Specification from an OpenAPI 3.x Specification"
7880
}
7981

8082
func (cmd *GenerateCommand) Run(args []string) int {
83+
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
84+
Level: slog.LevelWarn,
85+
}))
86+
8187
fs := cmd.Flags()
8288
err := fs.Parse(args)
8389
if err != nil {
84-
cmd.UI.Error(fmt.Sprintf("unable to parse flags: %s", err))
90+
logger.Error("error parsing flags", "err", err)
8591
return 1
8692
}
8793

8894
cmd.oasInputPath = fs.Arg(0)
8995
if cmd.oasInputPath == "" {
90-
cmd.UI.Error("Error executing command: OpenAPI specification file is required as last argument")
96+
logger.Error("error executing command", "err", "OpenAPI specification file is required as last argument")
9197
return 1
9298
}
9399

94-
err = cmd.runInternal()
100+
err = cmd.runInternal(logger)
95101
if err != nil {
96-
cmd.UI.Error(fmt.Sprintf("Error executing command: %s\n", err))
102+
logger.Error("error executing command", "err", err)
97103
return 1
98104
}
99105

100106
return 0
101107
}
102108

103-
func (cmd *GenerateCommand) runInternal() error {
109+
func (cmd *GenerateCommand) runInternal(logger *slog.Logger) error {
104110
// 1. Read and parse generator config file
105111
configBytes, err := os.ReadFile(cmd.flagConfigPath)
106112
if err != nil {
107-
return fmt.Errorf("failed to read generator config file: %w", err)
113+
return fmt.Errorf("error reading generator config file: %w", err)
108114
}
109115
config, err := config.ParseConfig(configBytes)
110116
if err != nil {
111-
return fmt.Errorf("failed to parse generator config file: %w", err)
117+
return fmt.Errorf("error parsing generator config file: %w", err)
112118
}
113119

114120
// 2. Read and parse OpenAPI spec file
115121
oasBytes, err := os.ReadFile(cmd.oasInputPath)
116122
if err != nil {
117-
return fmt.Errorf("failed to read OpenAPI spec file: %w", err)
123+
return fmt.Errorf("error reading OpenAPI spec file: %w", err)
118124
}
119125
doc, err := libopenapi.NewDocument(oasBytes)
120126
if err != nil {
121-
return fmt.Errorf("failed to parse OpenAPI spec file: %w", err)
127+
return fmt.Errorf("error parsing OpenAPI spec file: %w", err)
122128
}
123129

124130
// 3. Build out the OpenAPI model, this will recursively load all local + remote references into one cohesive model
125131
model, errs := doc.BuildV3Model()
126-
// TODO: Determine how to handle circular ref errors - https://pb33f.io/libopenapi/circular-references/
127-
if len(errs) > 0 {
128-
var errResult error
129-
for _, err := range errs {
130-
errResult = errors.Join(errResult, err)
132+
133+
// 4. Log circular references as warnings and fail on any other model building errors
134+
var errResult error
135+
for _, err := range errs {
136+
if rslvErr, ok := err.(*resolver.ResolvingError); ok {
137+
logger.Warn(
138+
"circular reference found in OpenAPI spec",
139+
"circular_ref", rslvErr.CircularReference.GenerateJourneyPath())
140+
continue
131141
}
132-
log.Printf("[WARN] Potential issues in model spec: %s", errResult)
142+
143+
errResult = errors.Join(errResult, err)
144+
}
145+
if errResult != nil {
146+
return fmt.Errorf("error building OpenAPI 3.x model: %w", errResult)
133147
}
134148

135-
// 4. Generate framework IR w/ config
149+
// 5. Generate provider code spec w/ config
136150
oasExplorer := explorer.NewConfigExplorer(model.Model, *config)
137-
frameworkIr, err := generateFrameworkIr(oasExplorer, *config)
151+
providerCodeSpec, err := generateProviderCodeSpec(logger, oasExplorer, *config)
138152
if err != nil {
139153
return err
140154
}
141155

142-
// 5. Use framework IR to create JSON
143-
bytes, err := json.MarshalIndent(frameworkIr, "", "\t")
156+
// 6. Use provider code spec to create JSON
157+
bytes, err := json.MarshalIndent(providerCodeSpec, "", "\t")
144158
if err != nil {
145-
return fmt.Errorf("error marshalling Framework IR to JSON: %w", err)
159+
return fmt.Errorf("error marshalling provider code spec to JSON: %w", err)
146160
}
147161

148-
// 6. Output to STDOUT or file
149-
if cmd.flagOutputPath == "" {
150-
cmd.UI.Output(string(bytes))
151-
return nil
162+
// 7. Log a warning if the provider code spec is not valid based on the JSON schema
163+
err = spec.Validate(context.Background(), bytes)
164+
if err != nil {
165+
logger.Warn(
166+
"generated provider code spec failed validation",
167+
"validation_msg", err)
152168
}
153169

170+
// 8. Output to file
154171
output, err := os.Create(cmd.flagOutputPath)
155172
if err != nil {
156-
return fmt.Errorf("error creating output file for Framework IR: %w", err)
173+
return fmt.Errorf("error creating output file for provider code spec: %w", err)
157174
}
158175

159176
_, err = output.Write(bytes)
160177
if err != nil {
161-
return fmt.Errorf("error writing framework IR to output: %w", err)
178+
return fmt.Errorf("error writing provider code spec to output: %w", err)
162179
}
163180

164181
return nil
165182
}
166183

167-
func generateFrameworkIr(dora explorer.Explorer, cfg config.Config) (*spec.Specification, error) {
168-
// 1. Find TF resources
184+
func generateProviderCodeSpec(logger *slog.Logger, dora explorer.Explorer, cfg config.Config) (*spec.Specification, error) {
185+
// 1. Find TF resources in OAS
169186
explorerResources, err := dora.FindResources()
170187
if err != nil {
171-
return nil, fmt.Errorf("error finding resources: %w", err)
188+
return nil, fmt.Errorf("error finding resource(s): %w", err)
172189
}
173190

174-
// 2. Find TF data sources
191+
// 2. Find TF data sources in OAS
175192
explorerDataSources, err := dora.FindDataSources()
176193
if err != nil {
177-
return nil, fmt.Errorf("error finding data sources: %w", err)
194+
return nil, fmt.Errorf("error finding data source(s): %w", err)
178195
}
179196

180-
// 3. Find TF provider
197+
// 3. Find TF provider in OAS
181198
explorerProvider, err := dora.FindProvider()
182199
if err != nil {
183200
return nil, fmt.Errorf("error finding provider: %w", err)
184201
}
185202

186-
// 4. Use TF info to generate framework IR for resources
203+
// 4. Use TF info to generate provider code spec for resources
187204
resourceMapper := mapper.NewResourceMapper(explorerResources, cfg)
188-
resourcesIR, err := resourceMapper.MapToIR()
205+
resourcesIR, err := resourceMapper.MapToIR(logger)
189206
if err != nil {
190-
return nil, fmt.Errorf("error generating Framework IR for resources: %w", err)
207+
return nil, fmt.Errorf("error generating provider code spec for resources: %w", err)
191208
}
192209

193-
// 5. Use TF info to generate framework IR for data sources
210+
// 5. Use TF info to generate provider code spec for data sources
194211
dataSourceMapper := mapper.NewDataSourceMapper(explorerDataSources, cfg)
195-
dataSourcesIR, err := dataSourceMapper.MapToIR()
212+
dataSourcesIR, err := dataSourceMapper.MapToIR(logger)
196213
if err != nil {
197-
return nil, fmt.Errorf("error generating Framework IR for data sources: %w", err)
214+
return nil, fmt.Errorf("error generating provider code spec for data sources: %w", err)
198215
}
199216

200-
// 6. Use TF info to generate framework IR for provider
217+
// 6. Use TF info to generate provider code spec for provider
201218
providerMapper := mapper.NewProviderMapper(explorerProvider, cfg)
202-
providerIR, err := providerMapper.MapToIR()
219+
providerIR, err := providerMapper.MapToIR(logger)
203220
if err != nil {
204-
return nil, fmt.Errorf("error generating Framework IR for provider: %w", err)
221+
return nil, fmt.Errorf("error generating provider code spec for provider: %w", err)
205222
}
206223

207224
return &spec.Specification{
225+
Version: spec.Version0_1,
208226
Provider: providerIR,
209227
Resources: resourcesIR,
210228
DataSources: dataSourcesIR,

0 commit comments

Comments
 (0)