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

Issue:
Allow disabling path uniqueness validation
## Problem statement

In an effort to have the go-swagger toolchain support the [resource name pattern described by Google's AIPs](https://cloud.google.com/apis/design/resource_names), I previously created this [PR](https://github.com/go-openapi/validate/pull/157) against the `go-openapi/validate` repo. I have been using a forking of this repo from 0.30.2 successfully since the PR was merged.

I was attempting to upstream it here but could not work through the errors. Link to patch: https://gist.github.com/dadgar/0ce4b7e49ffd34e9d74813a62f9f5f56

Applying the changes to v0.30.4 works but against `master` I get the following errors when generating the client:

```
$   swagger generate client -f swagger.json -t "$target" -A "cloud-iam" --allow-path-duplicates
...
2024/11/12 12:41:01 rendering 2 templates for operation cloud-iam
2024/11/12 12:41:01 name field AuthConfigService_CreateAuthConnection
2024/11/12 12:41:01 package field auth_config_service
2024/11/12 12:41:01 creating generated file "auth_config_service_create_auth_connection_parameters.go" in "../hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/auth_config_service" as parameters
2024/11/12 12:41:01 executed template asset:clientParameter
2024/11/12 12:41:01 source formatting failed on template-generated source ("../hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/auth_config_service/auth_config_service_create_auth_connection_parameters.go" for parameters). Check that your template produces valid code
2024/11/12 12:41:01 unformatted generated source "auth_config_service_create_auth_connection_parameters.go" has been dumped for template debugging purposes. DO NOT build on this source!
source formatting on generated source "parameters" failed: ../hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/auth_config_service/auth_config_service_create_auth_connection_parameters.go:86:20: expected ';', found string (and 3 more errors)
```

Here is the generated file: https://gist.github.com/dadgar/67b169e31e6c7707eb78353cf49ca6ad

## Swagger specification
https://gist.github.com/dadgar/29750c3506fad3528fc1a33de8059267

## Steps to reproduce

On a non patched version, simply run the `swagger generate client` against the linked swagger specification.

## Environment
swagger version: 0.31.0  
go version go1.23.1 darwin/arm64


Pull request:
Fix failing tests
Changes: 
- Fix broken links to OpenAPI-Specification
- revert #3122 

Unfortunately, have to revert #3122 due to the fact that it breaks tests. I guess on merging, due to the issue with tests running on a master branch instead of PR branch (see #3156) we didn't see that the PR tests were broken

Should be rebased after #3156 is merged to see that the tests pass, and only after that, we should merge this PR

Should fix #3142, as it is caused by changes in #3122

cc @casualjim 

Patch:
diff --git a/README.md b/README.md
index 717656fc..2e4b5375 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
 
 ---
 
-This project contains a golang implementation of Swagger 2.0 (aka [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md)).
+This project contains a golang implementation of Swagger 2.0 (aka [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md)).
 It provide tools to work with swagger specifications.
 
 [Swagger](https://swagger.io/) is a simple yet powerful representation of your RESTful API.<br>
diff --git a/doc.go b/doc.go
index 077b63d1..ab08ea16 100644
--- a/doc.go
+++ b/doc.go
@@ -39,7 +39,7 @@ The implementation also provides a number of command line tools to help working
 
 Currently there is a spec validator tool:
 
-	swagger validate https://raw.githubusercontent.com/swagger-api/swagger-spec/master/examples/v2.0/json/petstore-expanded.json
+	swagger validate https://raw.githubusercontent.com/swagger-api/swagger-spec/old-v3.2.0-dev/examples/v2.0/json/petstore-expanded.json
 
 To generate a server for a swagger spec document:
 
diff --git a/docs/_index.md b/docs/_index.md
index 49a2db9c..dc55aa8f 100644
--- a/docs/_index.md
+++ b/docs/_index.md
@@ -23,7 +23,7 @@ weight: 1
 
 ---
 
-This project contains a golang implementation of Swagger 2.0 (aka [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md)).
+This project contains a golang implementation of Swagger 2.0 (aka [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md)).
 It provide tools to work with swagger specifications.
 
 [Swagger](https://swagger.io/) is a simple yet powerful representation of your RESTful API.<br>
diff --git a/docs/faq/faq_swagger.md b/docs/faq/faq_swagger.md
index c3b376d7..c0f17020 100644
--- a/docs/faq/faq_swagger.md
+++ b/docs/faq/faq_swagger.md
@@ -220,7 +220,7 @@ Is it possible to bypass this validation error IF the operation ids will go into
 
 **Answer:** operationId is always globally unique per swagger 2.0 specification. The id MUST be unique among all operations described in the API.
 
-https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#operationObject
+https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md#operationObject
 
 > Unique string used to identify the operation. The id MUST be unique among all operations described in the API.
 > Tools and libraries MAY use the operationId to uniquely identify an operation,
diff --git a/docs/presentations/devconpulse.slide b/docs/presentations/devconpulse.slide
index 0783590f..465447ad 100644
--- a/docs/presentations/devconpulse.slide
+++ b/docs/presentations/devconpulse.slide
@@ -143,7 +143,7 @@ Server controlled documentation
 .link http://editor.swagger.io/ Swagger Editor
 .link http://petstore.swagger.io/ Swagger UI
 .link https://swaggerhub.com/ Swagger Hub (collaboration space)
-.link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md Specification
+.link https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md Specification
 .link https://openapis.org/ Open API Initiative
 .link https://any-api.com/ Documentation and testconsoles for 175 APIs
 
diff --git a/docs/presentations/golangsf.slide b/docs/presentations/golangsf.slide
index 4e1c4337..ea444946 100644
--- a/docs/presentations/golangsf.slide
+++ b/docs/presentations/golangsf.slide
@@ -136,7 +136,7 @@ Server controlled documentation
 .link http://editor.swagger.io/ Swagger Editor
 .link http://petstore.swagger.io/ Swagger UI
 .link https://swaggerhub.com/ Swagger Hub (collaboration space)
-.link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md Specification
+.link https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md Specification
 .link https://openapis.org/ Open API Initiative
 .link https://any-api.com/ Documentation and testconsoles for 175 APIs
 
diff --git a/docs/presentations/swagger-golangsf.html b/docs/presentations/swagger-golangsf.html
index 86f2df84..d621a967 100644
--- a/docs/presentations/swagger-golangsf.html
+++ b/docs/presentations/swagger-golangsf.html
@@ -412,7 +412,7 @@
       <article class="">
 
         <h3>Some resources</h3>
-        <p class="link"><a href="https://goswagger.io/" target="_blank">go-swagger documentation</a></p><p class="link"><a href="http://editor.swagger.io/" target="_blank">Swagger Editor</a></p><p class="link"><a href="http://petstore.swagger.io/" target="_blank">Swagger UI</a></p><p class="link"><a href="https://swaggerhub.com/" target="_blank">Swagger Hub (collaboration space)</a></p><p class="link"><a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md" target="_blank">Specification</a></p><p class="link"><a href="https://openapis.org/" target="_blank">Open API Initiative</a></p><p class="link"><a href="https://any-api.com/" target="_blank">Documentation and testconsoles for 175 APIs</a></p>
+        <p class="link"><a href="https://goswagger.io/" target="_blank">go-swagger documentation</a></p><p class="link"><a href="http://editor.swagger.io/" target="_blank">Swagger Editor</a></p><p class="link"><a href="http://petstore.swagger.io/" target="_blank">Swagger UI</a></p><p class="link"><a href="https://swaggerhub.com/" target="_blank">Swagger Hub (collaboration space)</a></p><p class="link"><a href="https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md" target="_blank">Specification</a></p><p class="link"><a href="https://openapis.org/" target="_blank">Open API Initiative</a></p><p class="link"><a href="https://any-api.com/" target="_blank">Documentation and testconsoles for 175 APIs</a></p>
 
       </article>
 
diff --git a/docs/reference/annotations/operation.md b/docs/reference/annotations/operation.md
index 9ed16862..d9c1c428 100644
--- a/docs/reference/annotations/operation.md
+++ b/docs/reference/annotations/operation.md
@@ -27,7 +27,7 @@ Any valid Swagger 2.0 YAML _Operation_ property is valid.
 Make sure your indentation is consistent and correct,
 as it won't parse correctly otherwise.
 
-You can find all the properties at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#operationObject
+You can find all the properties at https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md#operationObject
 
 Note that if you specify the _tags_, _summary_, _description_ or _operationId_ as part of the
 YAML spec, you will override the _summary_, _descriptions_, _tags_ or _operationId_, specified as part of the regular swagger syntax above.
diff --git a/docs/reference/models/schemas.md b/docs/reference/models/schemas.md
index b0494a29..357bcbf7 100644
--- a/docs/reference/models/schemas.md
+++ b/docs/reference/models/schemas.md
@@ -1331,7 +1331,7 @@ type ObjectWithDescription struct {
 ```
 
 
-[swagger]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schema-object
+[swagger]: https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md#schema-object
 [strfmt]: https://github.com/go-openapi/strfmt
 [runtime]: https://github.com/go-openapi/runtime
 [File]: https://github.com/go-openapi/runtime/blob/master/file.go#L20
@@ -1339,7 +1339,7 @@ type ObjectWithDescription struct {
 [validate]: https://github.com/go-openapi/validate
 [validate-json]: https://godoc.org/github.com/go-openapi/validate#ex-AgainstSchema
 [go-doc-model]: https://godoc.org/github.com/go-swagger/go-swagger/examples/generated/models
-[read-only]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-13
+[read-only]: https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/versions/2.0.md#fixed-fields-13
 [all-formats]:  https://github.com/go-openapi/strfmt/blob/master/README.md
 [easy-json]: https://github.com/mailru/easyjson
 [json-schema]: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
diff --git a/generator/model.go b/generator/model.go
index 1e3010d5..ca5b87a0 100644
--- a/generator/model.go
+++ b/generator/model.go
@@ -2059,23 +2059,22 @@ func (sg *schemaGenContext) makeGenSchema() error {
 			sg.GenSchema.ExtraImports[alias] = pkg
 		}
 
-		if tpe.IsEmbedded {
-			sg.GenSchema.IsAnonymous = true
+		if !tpe.IsEmbedded {
+			sg.GenSchema.resolvedType = tpe
+			sg.GenSchema.Required = sg.Required
+			// assume we validate everything but interface and io.Reader - validation may be disabled by using the noValidation hint
+			sg.GenSchema.HasValidations = !(tpe.IsInterface || tpe.IsStream || tpe.SkipExternalValidation)
+			sg.GenSchema.IsAliased = sg.GenSchema.HasValidations
+
+			log.Printf("INFO: type %s is external, with inferred spec type %s, referred to as %s", sg.GenSchema.Name, sg.GenSchema.GoType, extType)
+			sg.GenSchema.GoType = extType
+			sg.GenSchema.AliasedType = extType
+
+			// short circuit schema building for external types
+			return nil
 		}
-
-		sg.GenSchema.resolvedType = tpe
-		sg.GenSchema.Required = sg.Required
-		// assume we validate everything but interface and io.Reader - validation may be disabled by using the noValidation hint
-		sg.GenSchema.HasValidations = !(tpe.IsInterface || tpe.IsStream || tpe.SkipExternalValidation)
-		sg.GenSchema.IsAliased = sg.GenSchema.HasValidations
-
-		log.Printf("INFO: type %s is external, with inferred spec type %s, referred to as %s", sg.GenSchema.Name, sg.GenSchema.GoType, extType)
-		log.Printf("INFO: pkg: %s, alias: %s", pkg, alias)
-		sg.GenSchema.GoType = extType
-		sg.GenSchema.AliasedType = extType
-
-		// short circuit schema building for external types
-		return nil
+		// TODO: case for embedded types as anonymous definitions
+		return fmt.Errorf("ERROR: inline definitions embedded types are not supported")
 	}
 
 	debugLog("gschema nullable: %t", sg.GenSchema.IsNullable)
diff --git a/generator/structs.go b/generator/structs.go
index 85d52765..14522888 100644
--- a/generator/structs.go
+++ b/generator/structs.go
@@ -82,7 +82,6 @@ type GenSchema struct {
 	StrictAdditionalProperties bool
 	ReadOnly                   bool
 	IsVirtual                  bool
-	IsAnonymous                bool
 	IsBaseType                 bool
 	HasBaseType                bool
 	IsSubType                  bool
@@ -140,8 +139,6 @@ func (g GenSchema) PrintTags() string {
 		orderedTags = append(orderedTags, "xml")
 	}
 
-	customMap := getCustomTagKeyMap(g.CustomTag)
-
 	// Add extra struct tags, only if the tag hasn't already been set, i.e. example.
 	// Extra struct tags have the same value has the `json` tag.
 	for _, tag := range g.StructTags {
@@ -157,29 +154,12 @@ func (g GenSchema) PrintTags() string {
 		case tag == "description" && len(g.Description) > 0:
 			tags["description"] = g.Description
 		default:
-			if customMap[tag] {
-				// dedupe
-				continue
-			}
 			tags[tag] = tags["json"]
 		}
 
 		orderedTags = append(orderedTags, tag)
 	}
 
-	if customMap["json"] {
-		// avoid duplication
-		delete(tags, "json")
-		var newOrderedTags []string
-		for i, tag := range orderedTags {
-			if tag == "json" {
-				continue
-			}
-			newOrderedTags = append(newOrderedTags, orderedTags[i])
-		}
-		orderedTags = newOrderedTags
-	}
-
 	// Assemble the tags in key value pairs with the value properly quoted.
 	kvPairs := make([]string, 0, len(orderedTags)+1)
 	for _, key := range orderedTags {
diff --git a/generator/templates/structfield.gotmpl b/generator/templates/structfield.gotmpl
index ed12478d..c8e235dc 100644
--- a/generator/templates/structfield.gotmpl
+++ b/generator/templates/structfield.gotmpl
@@ -3,13 +3,7 @@
     // {{ template "docstring" . }}
     {{- template "propertyValidationDocString" .}}
   {{- end}}
-{{ if not $.IsAnonymous }}
 {{ pascalize .Name}} {{ template "schemaType" . }} {{ .PrintTags }}
-{{ else }}
-  {{- if and (not .IsMap) .IsNullable (not .IsSuperAlias) }}*{{ end }}
-  {{- if .IsSuperAlias }} = {{ end }}
-  {{- .GoType }} {{ .PrintTags }}
-{{ end }}
 {{ end }}
 
 {{- define "tuplefield" }}
diff --git a/generator/types.go b/generator/types.go
index 60c6d49f..5cc00f24 100644
--- a/generator/types.go
+++ b/generator/types.go
@@ -152,8 +152,7 @@ func (t typeResolver) knownDefGoType(def string, schema spec.Schema, clear func(
 		def = nm
 	}
 	extType, isExternalType := t.resolveExternalType(ext)
-	// if !isExternalType || extType.Embedded {
-	if !isExternalType {
+	if !isExternalType || extType.Embedded {
 		if clear == nil {
 			debugLog("known def type no clear: %q", def)
 			return def, t.definitionPkg, ""
diff --git a/generator/util.go b/generator/util.go
deleted file mode 100644
index 9f87ec2d..00000000
--- a/generator/util.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package generator
-
-import "strings"
-
-func getCustomTagKeyMap(tagStr string) map[string]bool {
-	res := map[string]bool{}
-	for {
-		output := strings.SplitN(tagStr, ":", 2)
-		if len(output) != 2 {
-			break
-		}
-		res[output[0]] = true
-		output = strings.SplitN(output[1], " ", 2)
-		if len(output) != 2 {
-			break
-		}
-		tagStr = output[1]
-	}
-
-	return res
-}


Test patch:
diff --git a/generator/client_test.go b/generator/client_test.go
index cc5bd838..b44af884 100644
--- a/generator/client_test.go
+++ b/generator/client_test.go
@@ -98,7 +98,7 @@ func Test_GenerateClient(t *testing.T) {
 
 		t.Run("should fail on bad content in spec (HTML, not json)", func(t *testing.T) {
 			opts := testClientGenOpts()
-			opts.Spec = "https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v2.0/json/petstore.json"
+			opts.Spec = "https://github.com/OAI/OpenAPI-Specification/blob/old-v3.2.0-dev/examples/v2.0/json/petstore.json"
 			require.Error(t,
 				GenerateClient(clientName, []string{}, []string{}, opts),
 			)
@@ -106,7 +106,7 @@ func Test_GenerateClient(t *testing.T) {
 
 		t.Run("should fail when no valid operation is selected", func(t *testing.T) {
 			opts := testClientGenOpts()
-			opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/yaml/petstore.yaml"
+			opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/old-v3.2.0-dev/examples/v2.0/yaml/petstore.yaml"
 			require.Error(t,
 				GenerateClient(clientName, []string{}, []string{"wrongOperationID"}, opts),
 			)
@@ -128,7 +128,7 @@ func Test_GenerateClient(t *testing.T) {
 
 		t.Run("from remote spec", func(t *testing.T) {
 			opts := testClientGenOpts()
-			opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/yaml/petstore.yaml"
+			opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/old-v3.2.0-dev/examples/v2.0/yaml/petstore.yaml"
 
 			tft, err := os.MkdirTemp(cwd, "generated")
 			require.NoError(t, err)
@@ -172,7 +172,7 @@ func Test_GenerateClient(t *testing.T) {
 
 		t.Run("should dump template data", func(t *testing.T) {
 			opts := testClientGenOpts()
-			opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/yaml/petstore.yaml"
+			opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/old-v3.2.0-dev/examples/v2.0/yaml/petstore.yaml"
 
 			origStdout := os.Stdout
 			defer func() {
diff --git a/generator/model_test.go b/generator/model_test.go
index fc98afa9..e97d7d23 100644
--- a/generator/model_test.go
+++ b/generator/model_test.go
@@ -178,8 +178,6 @@ func TestGenerateModel_SchemaField(t *testing.T) {
 	gmp.MinItems = &in2
 	gmp.UniqueItems = true
 	gmp.ReadOnly = true
-	gmp.CustomTag = "mytag:\"foobar,foobaz\" json:\",inline\""
-	require.NotNil(t, getCustomTagKeyMap(gmp.CustomTag))
 	gmp.StructTags = []string{"json", "db", "example"}
 	gmp.Example = "some example\""
 	tt.assertRender(&gmp, `// The title of the property
@@ -196,10 +194,9 @@ func TestGenerateModel_SchemaField(t *testing.T) {
 // Max Items: 30
 // Min Items: 30
 // Unique: true
-`+"SomeName string `db:\"some name\" example:\"some example\\\"\" mytag:\"foobar,foobaz\" json:\",inline\"`\n")
+`+"SomeName string `json:\"some name\" db:\"some name\" example:\"some example\\\"\" mytag:\"foobar,foobaz\"`\n")
 
 	gmp.Example = "some example``"
-	gmp.CustomTag = "db:\",inline\" mytag:\"foobar,foobaz\" json:\",inline\""
 	tt.assertRender(&gmp, `// The title of the property
 //
 // The description of the property
@@ -214,24 +211,7 @@ func TestGenerateModel_SchemaField(t *testing.T) {
 // Max Items: 30
 // Min Items: 30
 // Unique: true
-`+"SomeName string \"example:\\\"some example``\\\" db:\\\",inline\\\" mytag:\\\"foobar,foobaz\\\" json:\\\",inline\\\"\"\n")
-
-	gmp.IsAnonymous = true
-	tt.assertRender(&gmp, `// The title of the property
-//
-// The description of the property
-// Example: some example`+"``"+`
-// Required: true
-// Read Only: true
-// Maximum: < 10
-// Minimum: > 10
-// Max Length: 20
-// Min Length: 20
-// Pattern: \w[\w- ]+
-// Max Items: 30
-// Min Items: 30
-// Unique: true
-`+"string \"example:\\\"some example``\\\" db:\\\",inline\\\" mytag:\\\"foobar,foobaz\\\" json:\\\",inline\\\"\"\n")
+`+"SomeName string \"json:\\\"some name\\\" db:\\\"some name\\\" example:\\\"some example``\\\" mytag:\\\"foobar,foobaz\\\"\"\n")
 }
 
 var schTypeGenDataSimple = []struct {