Repository: go-swagger/go-swagger (go)

Issue:
Models not importing x-go-type for one of properties
## Problem statement

Currently I have a model that is not adding the import for the reference added in x-go-type. It does add the alias before the struct, but not the import. Curiously, it does work for all of the operations, just not this model. It is referencing the Error struct in a separate repo. Thanks in advance for the help

## Swagger specification

swagger.json
```
"Partial": {
      "type": "object",
      "required":[
        "a",
        "errors"
      ],
      "properties":{
        "a":{
          "type": "object",
          "$ref": "#/definitions/A"
        },
        "errors":{
          "type":"object",
          "properties": {
            "errors": {
              "type": "object",
              "$ref": "#/definitions/Error"
            },
            "errorAs": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      }
    },
...
// The error model. This gets imported correctly in the operations. But not in the model

"Error": {
      "description": "Standard error response object",
      "type": "object",
      "required": [
        "code"
      ],
      "properties": {
       //...
      },
      "x-go-type": {
        "import": {
          "package": "path/to/model",
          "alias": "swaggermodels"
        },
        "type": "Error"
      }
    },
```

The Partial model file
```
import (
	strfmt "github.com/go-openapi/strfmt"

	"github.com/go-openapi/errors"
	"github.com/go-openapi/swag"
	"github.com/go-openapi/validate"
)
...
type PartialErrors struct {

	// error domains
	ErrorAs []string `json:"errorAs"`

	// errors
	Errors *swaggermodels.Error `json:"errors,omitempty"`
}
```
## Environment
swagger version: master
go version: 1.11.2


Pull request description:
fix imports of external types, when used as dependency in properties, items, etc
Fixed imports of external types in models or inline operations when the external type is part of an inner construct (properties, items, etc).

* fixes #1897


Signed-off-by: Frederic BIDON <fredbi@yahoo.com>

Patch:
diff --git a/fixtures/bugs/1897/fixture-1897.yaml b/fixtures/bugs/1897/fixture-1897.yaml
new file mode 100644
index 00000000..da4fed49
--- /dev/null
+++ b/fixtures/bugs/1897/fixture-1897.yaml
@@ -0,0 +1,75 @@
+---
+swagger: "2.0"
+info:
+  title: "repro #1897"
+  version: "0.0.1"
+  description: "repro issue #1897"
+  license:
+    name: "Apache 2.0"
+    url: "http://www.apache.org/licenses/LICENSE-2.0.html"
+paths:
+  "/as-schema":
+    get:
+      responses:
+        201:
+          description: ok
+          schema:
+            $ref: "#/definitions/Partial"
+
+  "/inline1":
+    get:
+      responses:
+        201:
+          description: ok
+          schema:
+            type: object
+            required: [a, errors]
+            properties:
+              a:
+                $ref: "#/definitions/A"
+              errors:
+                type: object
+                properties:
+                  errors:
+                    $ref: "#/definitions/Error"
+                  errorAs:
+                    type: array
+                    items:
+                      type: string
+
+        400:
+          description: ok
+          schema:
+            $ref: "#/definitions/Error"
+
+definitions:
+  A:
+    type: string
+
+  Partial:
+    type: object
+    required: [a, errors]
+    properties:
+      a:
+        $ref: "#/definitions/A"
+      errors:
+        type: object
+        properties:
+          errors:
+            $ref: "#/definitions/Error"
+          errorAs:
+            type: array
+            items:
+              type: string
+  Error:
+    type: object
+    required: [code]
+    properties:
+      code:
+        type: integer
+    x-go-type:
+      type: Error
+      import:
+        package: github.com/go-swagger/go-swagger/fixtures/bugs/1897/external
+        alias: swaggermodels
+
diff --git a/fixtures/bugs/1897/model.yaml b/fixtures/bugs/1897/model.yaml
new file mode 100644
index 00000000..8461a909
--- /dev/null
+++ b/fixtures/bugs/1897/model.yaml
@@ -0,0 +1,7 @@
+definitions:
+  Error:
+    type: object
+    properties:
+      code:
+        type: integer
+        format: uint32
diff --git a/generator/model.go b/generator/model.go
index e5072e31..aff2aaf3 100644
--- a/generator/model.go
+++ b/generator/model.go
@@ -417,6 +417,9 @@ func findImports(sch *GenSchema) map[string]string {
 			}
 		}
 	}
+	for k, v := range sch.ExtraImports {
+		imp[k] = v
+	}
 	return imp
 }
 
@@ -718,6 +721,14 @@ func (sg *schemaGenContext) MergeResult(other *schemaGenContext, liftsRequired b
 	if other.GenSchema.IsMapNullOverride {
 		sg.GenSchema.IsMapNullOverride = true
 	}
+
+	// lift extra imports
+	if other.GenSchema.Pkg != "" && other.GenSchema.PkgAlias != "" {
+		sg.GenSchema.ExtraImports[other.GenSchema.PkgAlias] = other.GenSchema.Pkg
+	}
+	for k, v := range other.GenSchema.ExtraImports {
+		sg.GenSchema.ExtraImports[k] = v
+	}
 }
 
 func (sg *schemaGenContext) buildProperties() error {
@@ -1896,6 +1907,7 @@ func (sg *schemaGenContext) makeGenSchema() error {
 	sg.GenSchema.StrictAdditionalProperties = sg.StrictAdditionalProperties
 	sg.GenSchema.Default = sg.Schema.Default
 	sg.GenSchema.StructTags = sg.StructTags
+	sg.GenSchema.ExtraImports = make(map[string]string)
 
 	var err error
 	returns, err := sg.shortCircuitNamedRef()
diff --git a/generator/structs.go b/generator/structs.go
index dd9afa3c..16ae892f 100644
--- a/generator/structs.go
+++ b/generator/structs.go
@@ -93,6 +93,7 @@ type GenSchema struct {
 	Default                    interface{}
 	WantsMarshalBinary         bool // do we generate MarshalBinary interface?
 	StructTags                 []string
+	ExtraImports               map[string]string // non-standard imports detected when using external types
 }
 
 func (g GenSchemaList) Len() int      { return len(g) }


Test patch:
diff --git a/generator/generate_test.go b/generator/generate_test.go
index d97889bf..2396fbd3 100644
--- a/generator/generate_test.go
+++ b/generator/generate_test.go
@@ -237,6 +237,47 @@ func TestGenerateAndTest(t *testing.T) {
 				assert.True(t, fileExists(filepath.Join(target, "cmd", "custom-api"), "main.go"))
 			},
 		},
+		"external_model": {
+			spec:   "../fixtures/bugs/1897/fixture-1897.yaml",
+			target: "../fixtures/bugs/1897/codegen",
+			prepare: func(opts *GenOpts) {
+				modelOpts := testGenOpts()
+				modelOpts.AcceptDefinitionsOnly = true
+				modelOpts.Spec = "../fixtures/bugs/1897/model.yaml"
+				modelOpts.Spec = "../fixtures/bugs/1897/model.yaml"
+				modelOpts.Target = "../fixtures/bugs/1897"
+				modelOpts.ModelPackage = "external"
+				err := GenerateModels(nil, modelOpts)
+				require.NoError(t, err)
+				t.Logf("generated external model")
+				opts.IncludeMain = true
+			},
+			verify: func(t testing.TB, target string) {
+				defer func() {
+					_ = os.RemoveAll(target)
+				}()
+				require.True(t, fileExists(target, filepath.Join("..", "external")))
+				defer func() {
+					_ = os.RemoveAll(filepath.Join(target, "..", "external"))
+				}()
+
+				require.True(t, fileExists(target, filepath.Join("..", "external", "error.go")))
+				require.True(t, fileExists(target, filepath.Join("cmd", "repro1897-server")))
+
+				cwd, err := os.Getwd()
+				require.NoError(t, err)
+
+				err = os.Chdir(filepath.Join(target, "cmd", "repro1897-server"))
+				require.NoError(t, err)
+				defer func() {
+					_ = os.Chdir(cwd)
+				}()
+
+				t.Log("building generated server")
+				p, err := exec.Command("go", "build").CombinedOutput()
+				require.NoErrorf(t, err, string(p))
+			},
+		},
 	}
 
 	for name, cas := range cases {