diff --git a/.gitignore b/.gitignore index 5298fd94..a7d7e3b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ /.bin /build +integration/testdata/transitive-project-reference/**/bin +integration/testdata/transitive-project-reference/**/obj +integration/testdata/source-app/**/bin +integration/testdata/source-app/**/obj diff --git a/buildpack.toml b/buildpack.toml index fe0537a9..bcd38e16 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -28,21 +28,21 @@ api = "0.8" [[order.group]] id = "paketo-buildpacks/dotnet-core-runtime" - version = "0.8.0" + version = "0.10.0" [[order.group]] id = "paketo-buildpacks/dotnet-core-aspnet" optional = true - version = "0.7.0" + version = "0.9.0" [[order.group]] id = "paketo-buildpacks/dotnet-core-sdk" - version = "0.7.0" + version = "0.9.0" [[order.group]] id = "paketo-buildpacks/icu" optional = true - version = "0.2.1" + version = "0.3.0" [[order.group]] id = "paketo-buildpacks/node-engine" @@ -51,11 +51,11 @@ api = "0.8" [[order.group]] id = "paketo-buildpacks/dotnet-publish" - version = "0.7.4" + version = "0.8.0" [[order.group]] id = "paketo-buildpacks/dotnet-execute" - version = "0.9.0" + version = "0.10.1" [[order.group]] id = "paketo-buildpacks/procfile" @@ -86,22 +86,22 @@ api = "0.8" [[order.group]] id = "paketo-buildpacks/dotnet-core-runtime" - version = "0.8.0" + version = "0.10.0" [[order.group]] id = "paketo-buildpacks/dotnet-core-aspnet" optional = true - version = "0.7.0" + version = "0.9.0" [[order.group]] id = "paketo-buildpacks/dotnet-core-sdk" optional = true - version = "0.7.0" + version = "0.9.0" [[order.group]] id = "paketo-buildpacks/icu" optional = true - version = "0.2.1" + version = "0.3.0" [[order.group]] id = "paketo-buildpacks/node-engine" @@ -110,7 +110,7 @@ api = "0.8" [[order.group]] id = "paketo-buildpacks/dotnet-execute" - version = "0.9.0" + version = "0.10.1" [[order.group]] id = "paketo-buildpacks/procfile" @@ -142,7 +142,7 @@ api = "0.8" [[order.group]] id = "paketo-buildpacks/icu" optional = true - version = "0.2.1" + version = "0.3.0" [[order.group]] id = "paketo-buildpacks/node-engine" @@ -151,7 +151,7 @@ api = "0.8" [[order.group]] id = "paketo-buildpacks/dotnet-execute" - version = "0.9.0" + version = "0.10.1" [[order.group]] id = "paketo-buildpacks/procfile" diff --git a/integration/source_test.go b/integration/source_test.go index 27105197..06c526bd 100644 --- a/integration/source_test.go +++ b/integration/source_test.go @@ -31,7 +31,7 @@ func testSource(t *testing.T, context spec.G, it spec.S) { docker = occam.NewDocker() }) - context("when building a .Net core source code app that uses angular", func() { + context("when building from source", func() { var ( image occam.Image container occam.Container @@ -46,9 +46,6 @@ func testSource(t *testing.T, context spec.G, it spec.S) { name, err = occam.RandomName() Expect(err).NotTo(HaveOccurred()) - source, err = occam.Source(filepath.Join("testdata", "source-app")) - Expect(err).NotTo(HaveOccurred()) - sbomDir, err = os.MkdirTemp("", "sbom") Expect(err).NotTo(HaveOccurred()) Expect(os.Chmod(sbomDir, os.ModePerm)).To(Succeed()) @@ -63,187 +60,250 @@ func testSource(t *testing.T, context spec.G, it spec.S) { Expect(os.RemoveAll(sbomDir)).To(Succeed()) }) - it("creates a working OCI image", func() { - var err error - var logs fmt.Stringer - image, logs, err = pack.WithNoColor().Build. - WithBuildpacks(dotnetCoreBuildpack). - WithSBOMOutputDir(sbomDir). - WithPullPolicy("never"). - Execute(name, source) - Expect(err).NotTo(HaveOccurred(), logs.String()) - - container, err = docker.Container.Run. - WithEnv(map[string]string{"PORT": "8080"}). - WithPublish("8080"). - WithPublishAll(). - Execute(image.ID) - Expect(err).NotTo(HaveOccurred()) + context("when building a .Net core source code app that uses angular", func() { + it.Before(func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "source-app")) + Expect(err).NotTo(HaveOccurred()) + }) - Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("Node Engine Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Execute Buildpack"))) + it.After(func() { + Expect(os.RemoveAll(source)).To(Succeed()) + }) - Expect(logs).NotTo(ContainLines(ContainSubstring("Environment Variables Buildpack"))) - Expect(logs).NotTo(ContainLines(ContainSubstring("Image Labels Buildpack"))) + it("creates a working OCI image", func() { + var ( + err error + logs fmt.Stringer + ) + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(dotnetCoreBuildpack). + WithSBOMOutputDir(sbomDir). + WithPullPolicy("never"). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) - Eventually(container).Should(Serve(ContainSubstring("source_app")).OnPort(8080)) + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) - // check that all required SBOM files are present - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-runtime", "dotnet-core-runtime", "sbom.cdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-runtime", "dotnet-core-runtime", "sbom.spdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-runtime", "dotnet-core-runtime", "sbom.syft.json")).To(BeARegularFile()) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("Node Engine Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Execute Buildpack"))) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-aspnet", "dotnet-core-aspnet", "sbom.cdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-aspnet", "dotnet-core-aspnet", "sbom.spdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-aspnet", "dotnet-core-aspnet", "sbom.syft.json")).To(BeARegularFile()) + Expect(logs).NotTo(ContainLines(ContainSubstring("Environment Variables Buildpack"))) + Expect(logs).NotTo(ContainLines(ContainSubstring("Image Labels Buildpack"))) - Expect(filepath.Join(sbomDir, "sbom", "build", "paketo-buildpacks_dotnet-core-sdk", "dotnet-core-sdk", "sbom.cdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "build", "paketo-buildpacks_dotnet-core-sdk", "dotnet-core-sdk", "sbom.spdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "build", "paketo-buildpacks_dotnet-core-sdk", "dotnet-core-sdk", "sbom.syft.json")).To(BeARegularFile()) + Eventually(container).Should(Serve(ContainSubstring("source_app")).OnPort(8080)) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_icu", "icu", "sbom.cdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_icu", "icu", "sbom.spdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_icu", "icu", "sbom.syft.json")).To(BeARegularFile()) + // check that all required SBOM files are present + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-runtime", "dotnet-core-runtime", "sbom.cdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-runtime", "dotnet-core-runtime", "sbom.spdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-runtime", "dotnet-core-runtime", "sbom.syft.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_node-engine", "node", "sbom.cdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_node-engine", "node", "sbom.spdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_node-engine", "node", "sbom.syft.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-aspnet", "dotnet-core-aspnet", "sbom.cdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-aspnet", "dotnet-core-aspnet", "sbom.spdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-core-aspnet", "dotnet-core-aspnet", "sbom.syft.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-execute", "sbom.cdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-execute", "sbom.spdx.json")).To(BeARegularFile()) - Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-execute", "sbom.syft.json")).To(BeARegularFile()) - }) + Expect(filepath.Join(sbomDir, "sbom", "build", "paketo-buildpacks_dotnet-core-sdk", "dotnet-core-sdk", "sbom.cdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "build", "paketo-buildpacks_dotnet-core-sdk", "dotnet-core-sdk", "sbom.spdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "build", "paketo-buildpacks_dotnet-core-sdk", "dotnet-core-sdk", "sbom.syft.json")).To(BeARegularFile()) - context("when using ca certs buildpack", func() { - var ( - client *http.Client - ) - it.Before(func() { - var err error + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_icu", "icu", "sbom.cdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_icu", "icu", "sbom.spdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_icu", "icu", "sbom.syft.json")).To(BeARegularFile()) - // Remove source directory created in the it.Before - Expect(os.RemoveAll(source)).To(Succeed()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_node-engine", "node", "sbom.cdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_node-engine", "node", "sbom.spdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_node-engine", "node", "sbom.syft.json")).To(BeARegularFile()) - source, err = occam.Source(filepath.Join("testdata", "ca-cert-apps")) - Expect(err).NotTo(HaveOccurred()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-execute", "sbom.cdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-execute", "sbom.spdx.json")).To(BeARegularFile()) + Expect(filepath.Join(sbomDir, "sbom", "launch", "paketo-buildpacks_dotnet-execute", "sbom.syft.json")).To(BeARegularFile()) + }) - caCert, err := os.ReadFile(filepath.Join(source, "client-certs", "ca.pem")) - Expect(err).ToNot(HaveOccurred()) + context("when using ca certs buildpack", func() { + var ( + client *http.Client + ) + it.Before(func() { + var err error + + // Remove source directory created in the it.Before + Expect(os.RemoveAll(source)).To(Succeed()) + + source, err = occam.Source(filepath.Join("testdata", "ca-cert-apps")) + Expect(err).NotTo(HaveOccurred()) + + caCert, err := os.ReadFile(filepath.Join(source, "client-certs", "ca.pem")) + Expect(err).ToNot(HaveOccurred()) - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) - cert, err := tls.LoadX509KeyPair(filepath.Join(source, "client-certs", "cert.pem"), filepath.Join(source, "client-certs", "key.pem")) - Expect(err).ToNot(HaveOccurred()) + cert, err := tls.LoadX509KeyPair(filepath.Join(source, "client-certs", "cert.pem"), filepath.Join(source, "client-certs", "key.pem")) + Expect(err).ToNot(HaveOccurred()) - client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: caCertPool, - Certificates: []tls.Certificate{cert}, - MinVersion: tls.VersionTLS12, + client = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + Certificates: []tls.Certificate{cert}, + MinVersion: tls.VersionTLS12, + }, }, - }, - } - }) + } + }) - it("builds a working OCI image and uses a client-side CA cert for requests", func() { - var err error - var logs fmt.Stringer - image, logs, err = pack.WithNoColor().Build. - WithBuildpacks(dotnetCoreBuildpack). - WithPullPolicy("never"). - Execute(name, filepath.Join(source, "source-app")) - Expect(err).NotTo(HaveOccurred(), logs.String()) + it("builds a working OCI image and uses a client-side CA cert for requests", func() { + var err error + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(dotnetCoreBuildpack). + WithPullPolicy("never"). + Execute(name, filepath.Join(source, "source-app")) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + Expect(logs).To(ContainLines(ContainSubstring("CA Certificates Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Execute Buildpack"))) + + container, err = docker.Container.Run. + WithPublish("8080"). + WithEnv(map[string]string{ + "SERVICE_BINDING_ROOT": "/bindings", + }). + WithVolumes(fmt.Sprintf("%s:/bindings/ca-certificates", filepath.Join(source, "binding"))). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) - Expect(logs).To(ContainLines(ContainSubstring("CA Certificates Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Execute Buildpack"))) + Eventually(func() string { + cLogs, err := docker.Container.Logs.Execute(container.ID) + Expect(err).NotTo(HaveOccurred()) + return cLogs.String() + }).Should( + ContainSubstring("Added 1 additional CA certificate(s) to system truststore"), + ) - container, err = docker.Container.Run. - WithPublish("8080"). - WithEnv(map[string]string{ - "SERVICE_BINDING_ROOT": "/bindings", - }). - WithVolumes(fmt.Sprintf("%s:/bindings/ca-certificates", filepath.Join(source, "binding"))). - Execute(image.ID) - Expect(err).NotTo(HaveOccurred()) + request, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%s", container.HostPort("8080")), nil) + Expect(err).NotTo(HaveOccurred()) + + var response *http.Response + Eventually(func() error { + var err error + response, err = client.Do(request) + return err + }).Should(BeNil()) + defer response.Body.Close() - Eventually(func() string { - cLogs, err := docker.Container.Logs.Execute(container.ID) + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) Expect(err).NotTo(HaveOccurred()) - return cLogs.String() - }).Should( - ContainSubstring("Added 1 additional CA certificate(s) to system truststore"), - ) + Expect(string(content)).To(ContainSubstring("Hello World!")) + }) + }) - request, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%s", container.HostPort("8080")), nil) - Expect(err).NotTo(HaveOccurred()) + context("when using optional utility buildpacks", func() { + var procfileContainer occam.Container + it.Before(func() { + Expect(os.WriteFile(filepath.Join(source, "Procfile"), []byte("procfile: echo Procfile command"), 0644)).To(Succeed()) + }) + + it.After(func() { + Expect(docker.Container.Remove.Execute(procfileContainer.ID)).To(Succeed()) + }) - var response *http.Response - Eventually(func() error { + it("builds a working OCI image and run the app with the start command from the Procfile and other utility buildpacks", func() { var err error - response, err = client.Do(request) - return err - }).Should(BeNil()) - defer response.Body.Close() + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(dotnetCoreBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("Node Engine Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("Procfile Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("Environment Variables Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("Image Labels Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("Watchexec Buildpack"))) + + Expect(image.Buildpacks[10].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[10].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) - Expect(response.StatusCode).To(Equal(http.StatusOK)) + Eventually(container).Should(BeAvailable()) + Eventually(container).Should(Serve(ContainSubstring("source_app")).OnPort(8080)) - content, err := io.ReadAll(response.Body) - Expect(err).NotTo(HaveOccurred()) - Expect(string(content)).To(ContainSubstring("Hello World!")) + procfileContainer, err = docker.Container.Run. + WithEntrypoint("procfile"). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(func() string { + containerLogs, err := docker.Container.Logs.Execute(procfileContainer.ID) + Expect(err).NotTo(HaveOccurred()) + return containerLogs.String() + }).Should(ContainSubstring("Procfile command")) + }) }) }) - context("when using optional utility buildpacks", func() { - var procfileContainer occam.Container + context("when building an app with multiple project files that depend on each other", func() { it.Before(func() { - Expect(os.WriteFile(filepath.Join(source, "Procfile"), []byte("procfile: echo Procfile command"), 0644)).To(Succeed()) + var err error + source, err = occam.Source(filepath.Join("testdata", "transitive-project-reference")) + Expect(err).NotTo(HaveOccurred()) }) it.After(func() { - Expect(docker.Container.Remove.Execute(procfileContainer.ID)).To(Succeed()) + Expect(os.RemoveAll(source)).To(Succeed()) }) - it("builds a working OCI image and run the app with the start command from the Procfile and other utility buildpacks", func() { - var err error - var logs fmt.Stringer + it("resolves the transitive dependencies and builds correctly", func() { + var ( + err error + logs fmt.Stringer + ) image, logs, err = pack.WithNoColor().Build. WithBuildpacks(dotnetCoreBuildpack). + WithSBOMOutputDir(sbomDir). WithPullPolicy("never"). WithEnv(map[string]string{ - "BPE_SOME_VARIABLE": "some-value", - "BP_IMAGE_LABELS": "some-label=some-value", - "BP_LIVE_RELOAD_ENABLED": "true", + "BP_DOTNET_PROJECT_PATH": "./src/WebApi", }). Execute(name, source) Expect(err).NotTo(HaveOccurred(), logs.String()) - Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("Node Engine Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("Procfile Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("Environment Variables Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("Image Labels Buildpack"))) - Expect(logs).To(ContainLines(ContainSubstring("Watchexec Buildpack"))) - - Expect(image.Buildpacks[10].Key).To(Equal("paketo-buildpacks/environment-variables")) - Expect(image.Buildpacks[10].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) - Expect(image.Labels["some-label"]).To(Equal("some-value")) - container, err = docker.Container.Run. WithEnv(map[string]string{"PORT": "8080"}). WithPublish("8080"). @@ -251,19 +311,20 @@ func testSource(t *testing.T, context spec.G, it spec.S) { Execute(image.ID) Expect(err).NotTo(HaveOccurred()) - Eventually(container).Should(Serve(ContainSubstring("source_app")).OnPort(8080)) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core Runtime Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ASP.NET Core Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Core SDK Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring("ICU Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Publish Buildpack"))) + Expect(logs).To(ContainLines(ContainSubstring(".NET Execute Buildpack"))) - procfileContainer, err = docker.Container.Run. - WithEntrypoint("procfile"). - Execute(image.ID) - Expect(err).NotTo(HaveOccurred()) + Expect(logs).NotTo(ContainLines(ContainSubstring("Environment Variables Buildpack"))) + Expect(logs).NotTo(ContainLines(ContainSubstring("Image Labels Buildpack"))) - Eventually(func() string { - containerLogs, err := docker.Container.Logs.Execute(procfileContainer.ID) - Expect(err).NotTo(HaveOccurred()) - return containerLogs.String() - }).Should(ContainSubstring("Procfile command")) + Eventually(container).Should(BeAvailable()) + Eventually(container).Should(Serve(ContainSubstring("Chilly")).OnPort(8080).WithEndpoint("/weatherforecast")) }) }) }) + } diff --git a/integration/testdata/transitive-project-reference/README.md b/integration/testdata/transitive-project-reference/README.md new file mode 100644 index 00000000..71735f92 --- /dev/null +++ b/integration/testdata/transitive-project-reference/README.md @@ -0,0 +1,7 @@ +# Weather Forecast Web API + +This app is based on the Web Api sample app that is provided by running `dotnet +new webapi`. A set of interdependent project files has been added. WebApi +depends on ProjectReferenceA, and ProjectReferenceA depends on +ProjectReferenceB. This is a minimal app to test for the buggy behaviour +uncovered in https://github.com/paketo-buildpacks/dotnet-core/issues/670. diff --git a/integration/testdata/transitive-project-reference/WebApi.sln b/integration/testdata/transitive-project-reference/WebApi.sln new file mode 100644 index 00000000..8aa03c9c --- /dev/null +++ b/integration/testdata/transitive-project-reference/WebApi.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32112.339 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "src\WebApi\WebApi.csproj", "{E04FEBC9-0E0C-4759-9279-35DB8D1046C2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectReferenceA", "src\ProjectReferenceA\ProjectReferenceA.csproj", "{A536DC80-9970-4A07-8261-CD7A41638DAF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectReferenceB", "src\ProjectReferenceB\ProjectReferenceB.csproj", "{FB44FC5F-7EF8-437B-942D-CDD8A8938258}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E04FEBC9-0E0C-4759-9279-35DB8D1046C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E04FEBC9-0E0C-4759-9279-35DB8D1046C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E04FEBC9-0E0C-4759-9279-35DB8D1046C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E04FEBC9-0E0C-4759-9279-35DB8D1046C2}.Release|Any CPU.Build.0 = Release|Any CPU + {A536DC80-9970-4A07-8261-CD7A41638DAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A536DC80-9970-4A07-8261-CD7A41638DAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A536DC80-9970-4A07-8261-CD7A41638DAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A536DC80-9970-4A07-8261-CD7A41638DAF}.Release|Any CPU.Build.0 = Release|Any CPU + {FB44FC5F-7EF8-437B-942D-CDD8A8938258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB44FC5F-7EF8-437B-942D-CDD8A8938258}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB44FC5F-7EF8-437B-942D-CDD8A8938258}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB44FC5F-7EF8-437B-942D-CDD8A8938258}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F72D1AE2-D936-49A6-B918-A073E0B4FF5B} + EndGlobalSection +EndGlobal diff --git a/integration/testdata/transitive-project-reference/src/ProjectReferenceA/Class1.cs b/integration/testdata/transitive-project-reference/src/ProjectReferenceA/Class1.cs new file mode 100644 index 00000000..f881e437 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/ProjectReferenceA/Class1.cs @@ -0,0 +1,7 @@ +namespace ProjectReferenceA +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/integration/testdata/transitive-project-reference/src/ProjectReferenceA/ProjectReferenceA.csproj b/integration/testdata/transitive-project-reference/src/ProjectReferenceA/ProjectReferenceA.csproj new file mode 100644 index 00000000..10c37f18 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/ProjectReferenceA/ProjectReferenceA.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/integration/testdata/transitive-project-reference/src/ProjectReferenceB/Class1.cs b/integration/testdata/transitive-project-reference/src/ProjectReferenceB/Class1.cs new file mode 100644 index 00000000..720ee577 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/ProjectReferenceB/Class1.cs @@ -0,0 +1,7 @@ +namespace ProjectReferenceB +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/integration/testdata/transitive-project-reference/src/ProjectReferenceB/ProjectReferenceB.csproj b/integration/testdata/transitive-project-reference/src/ProjectReferenceB/ProjectReferenceB.csproj new file mode 100644 index 00000000..a34fb9ce --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/ProjectReferenceB/ProjectReferenceB.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/integration/testdata/transitive-project-reference/src/WebApi/Controllers/WeatherForecastController.cs b/integration/testdata/transitive-project-reference/src/WebApi/Controllers/WeatherForecastController.cs new file mode 100644 index 00000000..8f2f77f4 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace WebApi.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateTime.Now.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/integration/testdata/transitive-project-reference/src/WebApi/Program.cs b/integration/testdata/transitive-project-reference/src/WebApi/Program.cs new file mode 100644 index 00000000..cb3557e9 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/Program.cs @@ -0,0 +1,21 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.MapControllers(); + +app.Run(); diff --git a/integration/testdata/transitive-project-reference/src/WebApi/Properties/launchSettings.json b/integration/testdata/transitive-project-reference/src/WebApi/Properties/launchSettings.json new file mode 100644 index 00000000..dff3784c --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": false, + "iisExpress": { + "applicationUrl": "http://localhost:14958" + } + }, + "profiles": { + "WebApi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7064;http://localhost:5064", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/integration/testdata/transitive-project-reference/src/WebApi/WeatherForecast.cs b/integration/testdata/transitive-project-reference/src/WebApi/WeatherForecast.cs new file mode 100644 index 00000000..528d970f --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace WebApi +{ + public class WeatherForecast + { + public DateTime Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} \ No newline at end of file diff --git a/integration/testdata/transitive-project-reference/src/WebApi/WebApi.csproj b/integration/testdata/transitive-project-reference/src/WebApi/WebApi.csproj new file mode 100644 index 00000000..f8cf54d3 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/WebApi.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/integration/testdata/transitive-project-reference/src/WebApi/appsettings.Development.json b/integration/testdata/transitive-project-reference/src/WebApi/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/integration/testdata/transitive-project-reference/src/WebApi/appsettings.json b/integration/testdata/transitive-project-reference/src/WebApi/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/integration/testdata/transitive-project-reference/src/WebApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/package.toml b/package.toml index 96d78bc5..9613dfd7 100644 --- a/package.toml +++ b/package.toml @@ -3,25 +3,25 @@ uri = "build/buildpack.tgz" [[dependencies]] - uri = "urn:cnb:registry:paketo-buildpacks/dotnet-execute@0.9.0" + uri = "urn:cnb:registry:paketo-buildpacks/dotnet-execute@0.10.1" [[dependencies]] - uri = "urn:cnb:registry:paketo-buildpacks/dotnet-core-runtime@0.8.0" + uri = "urn:cnb:registry:paketo-buildpacks/dotnet-core-runtime@0.10.0" [[dependencies]] - uri = "urn:cnb:registry:paketo-buildpacks/dotnet-core-sdk@0.7.0" + uri = "urn:cnb:registry:paketo-buildpacks/dotnet-core-sdk@0.9.0" [[dependencies]] - uri = "urn:cnb:registry:paketo-buildpacks/icu@0.2.1" + uri = "urn:cnb:registry:paketo-buildpacks/icu@0.3.0" [[dependencies]] uri = "urn:cnb:registry:paketo-buildpacks/node-engine@0.13.0" [[dependencies]] - uri = "urn:cnb:registry:paketo-buildpacks/dotnet-core-aspnet@0.7.0" + uri = "urn:cnb:registry:paketo-buildpacks/dotnet-core-aspnet@0.9.0" [[dependencies]] - uri = "urn:cnb:registry:paketo-buildpacks/dotnet-publish@0.7.4" + uri = "urn:cnb:registry:paketo-buildpacks/dotnet-publish@0.8.0" [[dependencies]] uri = "urn:cnb:registry:paketo-buildpacks/procfile@5.2.0"