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

Issue:
Operation package will be name replaced with version[0-9]+ if the tag contains v[0-9]+
## Problem statement

Since [v0.31.0](https://github.com/go-swagger/go-swagger/releases/tag/v0.31.0), if the operation tag contains `v[0-9]+`, the operation package name will be replaced with `version[0-9]+`. For example, even if the tag is `aaav1bbb`, it will be replaced with `version1`. It is not possible to avoid the problem by using `x-go-operation-tag`. This bug was introduced by https://github.com/go-swagger/go-swagger/pull/3043.

I have confirmed that this problem can be avoided with https://github.com/rxnew/go-swagger/commit/67580be6a4e9c532a26e4ea798e92d8546390b77.

## Swagger specification

2.0

## Steps to reproduce

1. Specify `aaav1bbb` in the operation tags
2. Run `swagger generate server`

## Environment
swagger version: 0.31.0  
go version: 1.23.1  


Pull request:
Fix replacement of generated packages with a version
* Fixes #3143

TL,DR:
* tags like "v[nnn]" should generate "version[nnn}" packages
* but anything that matches "*v[nnn]*" doesn't need to be rewritten

Patch:
diff --git a/fixtures/bugs/3143/3143.yaml b/fixtures/bugs/3143/3143.yaml
new file mode 100644
index 00000000..447474ce
--- /dev/null
+++ b/fixtures/bugs/3143/3143.yaml
@@ -0,0 +1,45 @@
+swagger: '2.0'
+info:
+  version: '0.0.1'
+  title: Planting Service
+  description: Testing regression issue#3143
+  contact: {}
+host: www.example.com
+basePath: /
+securityDefinitions: {}
+schemes:
+- https
+consumes:
+- application/json
+produces:
+- application/json
+paths:
+  /healthz:
+    get:
+      description: Service health check
+      summary: Service health check
+      tags:
+      - av2on
+      operationId: Servicehealthcheck
+      deprecated: false
+      produces:
+      - application/json
+      parameters: []
+      responses:
+        default:
+          description: ''
+          headers: {}
+  /wizz:
+    get:
+      description: fake
+      summary: dummy
+      tags:
+      - trailingv2
+      deprecated: false
+      produces:
+      - application/json
+      parameters: []
+      responses:
+        default:
+          description: ''
+          headers: {}
diff --git a/generator/operation.go b/generator/operation.go
index 07ff8a23..a2098c37 100644
--- a/generator/operation.go
+++ b/generator/operation.go
@@ -1258,7 +1258,7 @@ func (b *codeGenOpBuilder) analyzeTags() (string, []string, bool) {
 	return tag, intersected, len(filter) == 0 || len(filter) > 0 && len(intersected) > 0
 }
 
-var versionedPkgRex = regexp.MustCompile(`(?i)(v)([0-9]+)`)
+var versionedPkgRex = regexp.MustCompile(`(?i)^(v)([0-9]+)$`)
 
 func maxInt(a, b int) int {
 	if a > b {


Test patch:
diff --git a/generator/generate_test.go b/generator/generate_test.go
index df98fb6f..6532dcbd 100644
--- a/generator/generate_test.go
+++ b/generator/generate_test.go
@@ -565,6 +565,33 @@ func generateFixtures(_ testing.TB) map[string]generateFixture {
 				location := filepath.Join(target, "cmd", "nrcodegen-server")
 				require.True(t, fileExists("", location))
 
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "version1")))
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "version3")))
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "v2_validations")))
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "v3_validations")))
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "v3_actual")))
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "v3_planned")))
+
+				t.Run("building generated server",
+					goExecInDir(location, "build"),
+				)
+			},
+		},
+		"tag_package_name_regression_3143": {
+			spec:   "../fixtures/bugs/3143/3143.yaml",
+			target: "server-3143",
+			prepare: func(_ *testing.T, opts *GenOpts) {
+				opts.MainPackage = "nrcodegen-server"
+				opts.IncludeMain = true
+				opts.ValidateSpec = true
+			},
+			verify: func(t *testing.T, target string) {
+				location := filepath.Join(target, "cmd", "nrcodegen-server")
+				require.True(t, fileExists("", location))
+
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "av2on")))
+				require.True(t, fileExists("", filepath.Join(target, "restapi", "operations", "trailingv2")))
+
 				t.Run("building generated server",
 					goExecInDir(location, "build"),
 				)