github.com/fastwego/offiaccount@v1.0.1/cmd/build.go (about) 1 // Copyright 2020 FastWeGo 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "flag" 19 "fmt" 20 "io/ioutil" 21 "net/url" 22 "os" 23 "path" 24 "regexp" 25 "strings" 26 27 "github.com/iancoleman/strcase" 28 ) 29 30 func main() { 31 var pkgFlag string 32 flag.StringVar(&pkgFlag, "package", "default", "") 33 flag.Parse() 34 for _, group := range apiConfig { 35 if group.Package == "oauth" { // 单独处理 oauth 模块 36 continue 37 } 38 39 if group.Package == pkgFlag { 40 build(group) 41 } 42 } 43 44 if pkgFlag == "apilist" { 45 apilist() 46 } 47 48 } 49 50 func apilist() { 51 for _, group := range apiConfig { 52 fmt.Printf("- %s(%s)\n", group.Name, group.Package) 53 for _, api := range group.Apis { 54 split := strings.Split(api.Request, " ") 55 parse, _ := url.Parse(split[1]) 56 57 if api.FuncName == "" { 58 api.FuncName = strcase.ToCamel(path.Base(parse.Path)) 59 } 60 61 godocLink := fmt.Sprintf("https://pkg.go.dev/github.com/fastwego/offiaccount/apis/%s?tab=doc#%s", group.Package, api.FuncName) 62 fmt.Printf("\t- [%s](%s) \n\t\t- [%s (%s)](%s)\n", api.Name, api.See, api.FuncName, parse.Path, godocLink) 63 } 64 } 65 } 66 67 func build(group ApiGroup) { 68 var funcs []string 69 var consts []string 70 var testFuncs []string 71 var exampleFuncs []string 72 73 for _, api := range group.Apis { 74 tpl := postFuncTpl 75 _FUNC_NAME_ := "" 76 _GET_PARAMS_ := "" 77 _GET_SUFFIX_PARAMS_ := "" 78 _UPLOAD_ := "media" 79 _FIELD_NAME_ := "" 80 _FIELDS_ := "" 81 _PAYLOAD_ := "" 82 switch { 83 case strings.Contains(api.Request, "GET http"): 84 tpl = getFuncTpl 85 case strings.Contains(api.Request, "POST http"): 86 tpl = postFuncTpl 87 case strings.Contains(api.Request, "POST(@media"): 88 tpl = postUploadFuncTpl 89 _UPLOAD_ = "media" 90 91 pattern := `POST\(@media\|field=(\S+)\) http` 92 reg := regexp.MustCompile(pattern) 93 matched := reg.FindAllStringSubmatch(api.Request, -1) 94 if matched != nil { 95 _FIELD_NAME_ = matched[0][1] 96 _PAYLOAD_ = ", payload []byte" 97 } 98 } 99 if len(api.GetParams) > 0 { 100 _GET_PARAMS_ = `, params url.Values` 101 //if strings.Contains(api.Request, "POST") { 102 // _GET_PARAMS_ = `, ` + _GET_PARAMS_ 103 //} 104 _GET_SUFFIX_PARAMS_ = `+ "?" + params.Encode()` 105 } 106 107 split := strings.Split(api.Request, " ") 108 parseUrl, _ := url.Parse(split[1]) 109 110 if api.FuncName == "" { 111 _FUNC_NAME_ = strcase.ToCamel(path.Base(parseUrl.Path)) 112 } else { 113 _FUNC_NAME_ = api.FuncName 114 } 115 116 tpl = strings.ReplaceAll(tpl, "_TITLE_", api.Name) 117 tpl = strings.ReplaceAll(tpl, "_DESCRIPTION_", api.Description) 118 tpl = strings.ReplaceAll(tpl, "_REQUEST_", api.Request) 119 tpl = strings.ReplaceAll(tpl, "_SEE_", api.See) 120 tpl = strings.ReplaceAll(tpl, "_FUNC_NAME_", _FUNC_NAME_) 121 tpl = strings.ReplaceAll(tpl, "_UPLOAD_", _UPLOAD_) 122 tpl = strings.ReplaceAll(tpl, "_GET_PARAMS_", _GET_PARAMS_) 123 tpl = strings.ReplaceAll(tpl, "_GET_SUFFIX_PARAMS_", _GET_SUFFIX_PARAMS_) 124 if _FIELD_NAME_ != "" { 125 _FIELDS_ = strings.ReplaceAll(fieldTpl, "_FIELD_NAME_", _FIELD_NAME_) 126 } 127 tpl = strings.ReplaceAll(tpl, "_FIELDS_", _FIELDS_) 128 tpl = strings.ReplaceAll(tpl, "_PAYLOAD_", _PAYLOAD_) 129 130 funcs = append(funcs, tpl) 131 132 tpl = strings.ReplaceAll(constTpl, "_FUNC_NAME_", _FUNC_NAME_) 133 tpl = strings.ReplaceAll(tpl, "_API_PATH_", parseUrl.Path) 134 135 consts = append(consts, tpl) 136 137 // TestFunc 138 _TEST_ARGS_STRUCT_ := "" 139 switch { 140 case strings.Contains(api.Request, "GET http"): 141 _TEST_ARGS_STRUCT_ = `ctx *offiaccount.OffiAccount, ` + _GET_PARAMS_ 142 case strings.Contains(api.Request, "POST http"): 143 _TEST_ARGS_STRUCT_ = `ctx *offiaccount.OffiAccount, payload []byte` 144 if _GET_PARAMS_ != "" { 145 _TEST_ARGS_STRUCT_ += `,` + _GET_PARAMS_ 146 } 147 case strings.Contains(api.Request, "POST(@media"): 148 _TEST_ARGS_STRUCT_ = `ctx *offiaccount.OffiAccount, ` + _UPLOAD_ + ` string` + _PAYLOAD_ + _GET_PARAMS_ 149 } 150 _TEST_ARGS_STRUCT_ = strings.ReplaceAll(_TEST_ARGS_STRUCT_, ",", "\n") 151 152 _TEST_FUNC_SIGNATURE_ := "" 153 _EXAMPLE_ARGS_STMT_ := "" 154 if strings.TrimSpace(_TEST_ARGS_STRUCT_) != "" { 155 signatures := strings.Split(_TEST_ARGS_STRUCT_, "\n") 156 paramNames := []string{} 157 exampleStmt := []string{} 158 for _, signature := range signatures { 159 signature = strings.TrimSpace(signature) 160 tmp := strings.Split(signature, " ") 161 //fmt.Println(tmp) 162 if len(tmp[0]) > 0 { 163 paramNames = append(paramNames, "tt.args."+tmp[0]) 164 165 switch tmp[1] { 166 case `[]byte`: 167 exampleStmt = append(exampleStmt, tmp[0]+" := []byte(\"{}\")") 168 case `string`: 169 exampleStmt = append(exampleStmt, tmp[0]+" := \"\"") 170 case `url.Values`: 171 exampleStmt = append(exampleStmt, tmp[0]+" := url.Values{}") 172 } 173 } 174 } 175 _TEST_FUNC_SIGNATURE_ = strings.Join(paramNames, ",") 176 _EXAMPLE_ARGS_STMT_ = strings.Join(exampleStmt, "\n") 177 } 178 179 tpl = strings.ReplaceAll(testFuncTpl, "_FUNC_NAME_", _FUNC_NAME_) 180 tpl = strings.ReplaceAll(tpl, "_TEST_ARGS_STRUCT_", _TEST_ARGS_STRUCT_) 181 tpl = strings.ReplaceAll(tpl, "_TEST_FUNC_SIGNATURE_", _TEST_FUNC_SIGNATURE_) 182 testFuncs = append(testFuncs, tpl) 183 184 //Example 185 tpl = strings.ReplaceAll(exampleFuncTpl, "_FUNC_NAME_", _FUNC_NAME_) 186 tpl = strings.ReplaceAll(tpl, "_PACKAGE_", path.Base(group.Package)) 187 tpl = strings.ReplaceAll(tpl, "_TEST_FUNC_SIGNATURE_", strings.ReplaceAll(_TEST_FUNC_SIGNATURE_, "tt.args.", "")) 188 tpl = strings.ReplaceAll(tpl, "_EXAMPLE_ARGS_STMT_", _EXAMPLE_ARGS_STMT_) 189 exampleFuncs = append(exampleFuncs, tpl) 190 191 } 192 193 fileContent := fmt.Sprintf(fileTpl, path.Base(group.Package), group.Name, path.Base(group.Package), strings.Join(consts, ``), strings.Join(funcs, ``)) 194 filename := "./../apis/" + group.Package + "/" + path.Base(group.Package) + ".go" 195 _ = os.MkdirAll(path.Dir(filename), 0644) 196 err := ioutil.WriteFile(filename, []byte(fileContent), 0644) 197 if err != nil { 198 fmt.Println(err.Error()) 199 return 200 } 201 202 // output Test 203 testFileContent := fmt.Sprintf(testFileTpl, path.Base(group.Package), strings.Join(testFuncs, ``)) 204 //fmt.Println(testFileContent) 205 err = ioutil.WriteFile("./../apis/"+group.Package+"/"+path.Base(group.Package)+"_test.go", []byte(testFileContent), 0644) 206 if err != nil { 207 fmt.Println(err.Error()) 208 return 209 } 210 // output example 211 exampleFileContent := fmt.Sprintf(exampleFileTpl, path.Base(group.Package), strings.Join(exampleFuncs, ``)) 212 //fmt.Println(testFileContent) 213 err = ioutil.WriteFile("./../apis/"+group.Package+"/example_"+path.Base(group.Package)+"_test.go", []byte(exampleFileContent), 0644) 214 if err != nil { 215 fmt.Println(err.Error()) 216 return 217 } 218 } 219 220 var constTpl = ` 221 api_FUNC_NAME_ = "_API_PATH_"` 222 var commentTpl = ` 223 /* 224 _TITLE_ 225 226 _DESCRIPTION_ 227 228 See: _SEE_ 229 230 _REQUEST_ 231 */` 232 var postFuncTpl = commentTpl + ` 233 func _FUNC_NAME_(ctx *offiaccount.OffiAccount, payload []byte_GET_PARAMS_) (resp []byte, err error) { 234 return ctx.Client.HTTPPost(api_FUNC_NAME__GET_SUFFIX_PARAMS_, bytes.NewReader(payload), "application/json;charset=utf-8") 235 } 236 ` 237 var getFuncTpl = commentTpl + ` 238 func _FUNC_NAME_(ctx *offiaccount.OffiAccount_GET_PARAMS_) (resp []byte, err error) { 239 return ctx.Client.HTTPGet(api_FUNC_NAME__GET_SUFFIX_PARAMS_) 240 } 241 ` 242 var postUploadFuncTpl = commentTpl + ` 243 func _FUNC_NAME_(ctx *offiaccount.OffiAccount, _UPLOAD_ string_PAYLOAD__GET_PARAMS_) (resp []byte, err error) { 244 r, w := io.Pipe() 245 m := multipart.NewWriter(w) 246 go func() { 247 defer w.Close() 248 defer m.Close() 249 250 part, err := m.CreateFormFile("_UPLOAD_", path.Base(_UPLOAD_)) 251 if err != nil { 252 return 253 } 254 file, err := os.Open(_UPLOAD_) 255 if err != nil { 256 return 257 } 258 defer file.Close() 259 if _, err = io.Copy(part, file); err != nil { 260 return 261 } 262 263 _FIELDS_ 264 }() 265 return ctx.Client.HTTPPost(api_FUNC_NAME__GET_SUFFIX_PARAMS_, r, m.FormDataContentType()) 266 } 267 ` 268 269 var fieldTpl = ` 270 // field 271 err = m.WriteField("_FIELD_NAME_", string(payload)) 272 if err != nil { 273 return 274 } 275 ` 276 277 var fileTpl = `// Package %s %s 278 package %s 279 280 const ( 281 %s 282 ) 283 %s` 284 285 var testFileTpl = `package %s 286 287 func TestMain(m *testing.M) { 288 test.Setup() 289 os.Exit(m.Run()) 290 } 291 292 %s 293 ` 294 295 var testFuncTpl = ` 296 func Test_FUNC_NAME_(t *testing.T) { 297 mockResp := map[string][]byte{ 298 "case1": []byte("{\"errcode\":0,\"errmsg\":\"ok\"}"), 299 } 300 var resp []byte 301 test.MockSvrHandler.HandleFunc(api_FUNC_NAME_, func(w http.ResponseWriter, r *http.Request) { 302 w.Write([]byte(resp)) 303 }) 304 305 type args struct { 306 _TEST_ARGS_STRUCT_ 307 } 308 tests := []struct { 309 name string 310 args args 311 wantResp []byte 312 wantErr bool 313 }{ 314 {name: "case1", args: args{ctx: test.MockOffiAccount}, wantResp: mockResp["case1"], wantErr: false}, 315 } 316 for _, tt := range tests { 317 t.Run(tt.name, func(t *testing.T) { 318 resp = mockResp[tt.name] 319 gotResp, err := _FUNC_NAME_(_TEST_FUNC_SIGNATURE_) 320 //fmt.Println(string(gotResp), err) 321 if (err != nil) != tt.wantErr { 322 t.Errorf("_FUNC_NAME_() error = %v, wantErr %v", err, tt.wantErr) 323 return 324 } 325 if !reflect.DeepEqual(gotResp, tt.wantResp) { 326 t.Errorf("_FUNC_NAME_() gotResp = %v, want %v", gotResp, tt.wantResp) 327 } 328 }) 329 } 330 }` 331 332 var exampleFileTpl = `package %s_test 333 334 %s 335 ` 336 var exampleFuncTpl = ` 337 func Example_FUNC_NAME_() { 338 var ctx *offiaccount.OffiAccount 339 340 _EXAMPLE_ARGS_STMT_ 341 resp, err := _PACKAGE_._FUNC_NAME_(_TEST_FUNC_SIGNATURE_) 342 343 fmt.Println(resp, err) 344 } 345 346 `