Repository: goadesign/goa (go)

Issue:
bug: Using  no relative path prefix produces wrong code `dsl.Files`
Goa is awesome, but we have seen an issue which occures when doing:

```go
	dsl.Files("/mysuperduperapi.json", "a/b/c/openapi3.json")
```

The code does produces ([code])(https://github.com/goadesign/examples/blob/master/basic/gen/http/calc/server/server.go#L56)

```go
	fileSystemPkgGenHTTPOpenapi3JSON = appendPrefix(fileSystemPkgGenHTTPOpenapi3JSON, "/a/b/c")
```

but if the `a/b/c/` is dropped, e.g. `dsl.Files("/mysuperduperapi.json", "openapi3.json")`

Goa does not generate the `appendPrefix` which does not result in selecting the `openapi3.json` but trying to access `mysuperduperapi.json` (**instead of `openapi.json`**)
So I think `appendPrefix` should always be generate even if its with `"."` to select the `openapi3.json`.

P.S. Maybe this is also intended behavior, but its kind of odd, because only 

- `dsl.Files("/openapi3.json", "openapi3.json")` **works**
- `dsl.Files("/openapi.json", "openapi3.json")` **does not work**

This is triggered by [this line basically](https://github.com/goadesign/goa/blob/v3/http/codegen/templates/server_init.go.tpl#L35)






Pull request description:
Properly handle root files rename
when serving files via HTTP file server.
Fix #3663

Patch:
diff --git a/http/codegen/templates/server_init.go.tpl b/http/codegen/templates/server_init.go.tpl
index a80ce6c7..0562b3bc 100644
--- a/http/codegen/templates/server_init.go.tpl
+++ b/http/codegen/templates/server_init.go.tpl
@@ -32,9 +32,7 @@ func {{ .ServerInit }}(
 		{{- if not .IsDir }}
 			{{- $prefix = dir $prefix }}
 		{{- end }}
-		{{- if ne $prefix "/" }}
-	{{ .ArgName }} = appendPrefix({{ .ArgName }}, "{{ $prefix }}")
-		{{- end }}
+		{{ .ArgName }} = appendPrefix({{ .ArgName }}, "{{ $prefix }}")
 	{{- end }}
 	return &{{ .ServerStruct }}{
 		Mounts: []*{{ .MountPointStruct }}{


Test patch:
diff --git a/http/codegen/server_init_test.go b/http/codegen/server_init_test.go
index 3d2d6f97..e9225572 100644
--- a/http/codegen/server_init_test.go
+++ b/http/codegen/server_init_test.go
@@ -24,6 +24,7 @@ func TestServerInit(t *testing.T) {
 		{"multiple bases", testdata.ServerMultiBasesDSL, testdata.ServerMultiBasesConstructorCode, 2, 3},
 		{"file server", testdata.ServerFileServerDSL, testdata.ServerFileServerConstructorCode, 1, 3},
 		{"file server with a redirect", testdata.ServerFileServerWithRedirectDSL, testdata.ServerFileServerConstructorCode, 1, 3},
+		{"file server with root path", testdata.ServerFileServerRootPathDSL, testdata.ServerFileServerRootPathConstructorCode, 1, 3},
 		{"mixed", testdata.ServerMixedDSL, testdata.ServerMixedConstructorCode, 2, 3},
 		{"multipart", testdata.ServerMultipartDSL, testdata.ServerMultipartConstructorCode, 2, 4},
 		{"streaming", testdata.StreamingResultDSL, testdata.ServerStreamingConstructorCode, 3, 3},
diff --git a/http/codegen/testdata/server_dsls.go b/http/codegen/testdata/server_dsls.go
index 440d0397..8f9a3a5f 100644
--- a/http/codegen/testdata/server_dsls.go
+++ b/http/codegen/testdata/server_dsls.go
@@ -168,6 +168,18 @@ var ServerFileServerWithRedirectDSL = func() {
 	})
 }
 
+var ServerFileServerRootPathDSL = func() {
+	Service("ServiceFileServer", func() {
+		HTTP(func() {
+			Path("/")
+		})
+		Files("/file1.json", "file1.json")
+		Files("/path/to/file1.json", "file1.json")
+		Files("/file2.json", "file1.json")
+		Files("/path/to/file2.json", "file1.json")
+	})
+}
+
 var ServerMixedDSL = func() {
 	Service("ServerMixed", func() {
 		Method("MethodMixed1", func() {
diff --git a/http/codegen/testdata/server_init_functions.go b/http/codegen/testdata/server_init_functions.go
index 2a9e03fd..a3cce767 100644
--- a/http/codegen/testdata/server_init_functions.go
+++ b/http/codegen/testdata/server_init_functions.go
@@ -49,6 +49,55 @@ func New(
 }
 `
 
+const ServerFileServerRootPathConstructorCode = `// New instantiates HTTP handlers for all the ServiceFileServer service
+// endpoints using the provided encoder and decoder. The handlers are mounted
+// on the given mux using the HTTP verb and path defined in the design.
+// errhandler is called whenever a response fails to be encoded. formatter is
+// used to format errors returned by the service methods prior to encoding.
+// Both errhandler and formatter are optional and can be nil.
+func New(
+	e *servicefileserver.Endpoints,
+	mux goahttp.Muxer,
+	decoder func(*http.Request) goahttp.Decoder,
+	encoder func(context.Context, http.ResponseWriter) goahttp.Encoder,
+	errhandler func(context.Context, http.ResponseWriter, error),
+	formatter func(ctx context.Context, err error) goahttp.Statuser,
+	fileSystemFile1JSON http.FileSystem,
+	fileSystemFile1JSON2 http.FileSystem,
+	fileSystemFile1JSON3 http.FileSystem,
+	fileSystemFile1JSON4 http.FileSystem,
+) *Server {
+	if fileSystemFile1JSON == nil {
+		fileSystemFile1JSON = http.Dir(".")
+	}
+	fileSystemFile1JSON = appendPrefix(fileSystemFile1JSON, "/")
+	if fileSystemFile1JSON2 == nil {
+		fileSystemFile1JSON2 = http.Dir(".")
+	}
+	fileSystemFile1JSON2 = appendPrefix(fileSystemFile1JSON2, "/")
+	if fileSystemFile1JSON3 == nil {
+		fileSystemFile1JSON3 = http.Dir(".")
+	}
+	fileSystemFile1JSON3 = appendPrefix(fileSystemFile1JSON3, "/")
+	if fileSystemFile1JSON4 == nil {
+		fileSystemFile1JSON4 = http.Dir(".")
+	}
+	fileSystemFile1JSON4 = appendPrefix(fileSystemFile1JSON4, "/")
+	return &Server{
+		Mounts: []*MountPoint{
+			{"Serve file1.json", "GET", "/file1.json"},
+			{"Serve file1.json", "GET", "/path/to/file1.json"},
+			{"Serve file1.json", "GET", "/file2.json"},
+			{"Serve file1.json", "GET", "/path/to/file2.json"},
+		},
+		File1JSON:  http.FileServer(fileSystemFile1JSON),
+		File1JSON2: http.FileServer(fileSystemFile1JSON2),
+		File1JSON3: http.FileServer(fileSystemFile1JSON3),
+		File1JSON4: http.FileServer(fileSystemFile1JSON4),
+	}
+}
+`
+
 var ServerFileServerConstructorCode = `// New instantiates HTTP handlers for all the ServiceFileServer service
 // endpoints using the provided encoder and decoder. The handlers are mounted
 // on the given mux using the HTTP verb and path defined in the design.