diff --git a/install_process.go b/install_process.go index d8d11cd4..ad764ffb 100644 --- a/install_process.go +++ b/install_process.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "io" "os" "path/filepath" "strings" @@ -53,15 +54,17 @@ func (ip YarnInstallProcess) ShouldRun(workingDir string, metadata map[string]in ip.logger.Break() buffer := bytes.NewBuffer(nil) + listArgs := []string{"config", "list", "--silent"} + ip.logger.Subprocess("Running 'yarn %s'", strings.Join(listArgs, " ")) err = ip.executable.Execute(pexec.Execution{ - Args: []string{"config", "list", "--silent"}, - Stdout: buffer, - Stderr: buffer, + Args: listArgs, + Stdout: io.MultiWriter(ip.logger.ActionWriter, buffer), + Stderr: io.MultiWriter(ip.logger.ActionWriter, buffer), Dir: workingDir, }) if err != nil { - return true, "", fmt.Errorf("failed to execute yarn config output:\n%s\nerror: %s", buffer.String(), err) + return true, "", fmt.Errorf("failed to execute yarn config output:\nerror: %s", err) } nodeEnv := os.Getenv("NODE_ENV") @@ -144,15 +147,18 @@ func (ip YarnInstallProcess) Execute(workingDir, modulesLayerPath string, launch environment = append(environment, fmt.Sprintf("PATH=%s%c%s", os.Getenv("PATH"), os.PathListSeparator, filepath.Join("node_modules", ".bin"))) buffer := bytes.NewBuffer(nil) + configArgs := []string{"config", "get", "yarn-offline-mirror"} + ip.logger.Subprocess("Running 'yarn %s'", strings.Join(configArgs, " ")) + err := ip.executable.Execute(pexec.Execution{ - Args: []string{"config", "get", "yarn-offline-mirror"}, - Stdout: buffer, - Stderr: buffer, + Args: configArgs, + Stdout: io.MultiWriter(ip.logger.ActionWriter, buffer), + Stderr: io.MultiWriter(ip.logger.ActionWriter, buffer), Env: environment, Dir: workingDir, }) if err != nil { - return fmt.Errorf("failed to execute yarn config output:\n%s\nerror: %s", buffer.String(), err) + return fmt.Errorf("failed to execute yarn config output:\nerror: %s", err) } installArgs := []string{"install", "--ignore-engines", "--frozen-lockfile"} @@ -181,18 +187,16 @@ func (ip YarnInstallProcess) Execute(workingDir, modulesLayerPath string, launch } installArgs = append(installArgs, "--modules-folder", filepath.Join(modulesLayerPath, "node_modules")) - ip.logger.Subprocess("Running yarn %s", strings.Join(installArgs, " ")) + ip.logger.Subprocess("Running 'yarn %s'", strings.Join(installArgs, " ")) - buffer = bytes.NewBuffer(nil) err = ip.executable.Execute(pexec.Execution{ Args: installArgs, Env: environment, - Stdout: buffer, - Stderr: buffer, + Stdout: ip.logger.ActionWriter, + Stderr: ip.logger.ActionWriter, Dir: workingDir, }) if err != nil { - ip.logger.Action("%s", buffer) return fmt.Errorf("failed to execute yarn install: %w", err) } diff --git a/install_process_test.go b/install_process_test.go index 7a094de8..2eaff3d3 100644 --- a/install_process_test.go +++ b/install_process_test.go @@ -16,6 +16,7 @@ import ( "github.com/sclevine/spec" . "github.com/onsi/gomega" + . "github.com/paketo-buildpacks/occam/matchers" ) func testInstallProcess(t *testing.T, context spec.G, it spec.S) { @@ -27,6 +28,7 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { executable *fakes.Executable installProcess yarninstall.YarnInstallProcess summer *fakes.Summer + buffer *bytes.Buffer execution pexec.Execution ) @@ -40,13 +42,15 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { executable = &fakes.Executable{} summer = &fakes.Summer{} + buffer = bytes.NewBuffer(nil) executable.ExecuteCall.Stub = func(exec pexec.Execution) error { execution = exec fmt.Fprintln(exec.Stdout, "undefined") + fmt.Fprintln(exec.Stderr, "undefined") return nil } - installProcess = yarninstall.NewYarnInstallProcess(executable, summer, scribe.NewEmitter(bytes.NewBuffer(nil))) + installProcess = yarninstall.NewYarnInstallProcess(executable, summer, scribe.NewEmitter(buffer)) }) context("we should run yarn install when", func() { @@ -59,6 +63,7 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { Expect(run).To(BeTrue()) Expect(sha).To(Equal("")) Expect(err).NotTo(HaveOccurred()) + Expect(buffer.String()).ToNot(ContainLines(" Running 'yarn config list --silent'")) }) }) @@ -85,6 +90,11 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { "--silent", })) Expect(execution.Dir).To(Equal(workingDir)) + Expect(buffer.String()).To(ContainLines( + " Running 'yarn config list --silent'", + " undefined", + " undefined", + )) }) it("succeeds when sha is missing", func() { @@ -92,6 +102,11 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { Expect(run).To(BeTrue()) Expect(sha).To(Equal("some-other-sha")) Expect(err).NotTo(HaveOccurred()) + Expect(buffer.String()).To(ContainLines( + " Running 'yarn config list --silent'", + " undefined", + " undefined", + )) }) }) @@ -110,6 +125,11 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { Expect(run).To(BeFalse()) Expect(sha).To(Equal("")) Expect(err).NotTo(HaveOccurred()) + Expect(buffer.String()).To(ContainLines( + " Running 'yarn config list --silent'", + " undefined", + " undefined", + )) }) }) @@ -317,6 +337,8 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { executable = &fakes.Executable{} executable.ExecuteCall.Stub = func(execution pexec.Execution) error { executions = append(executions, execution) + fmt.Fprintln(execution.Stdout, "stdout output") + fmt.Fprintln(execution.Stderr, "stderr output") if strings.Contains(strings.Join(execution.Args, " "), "yarn-offline-mirror") { fmt.Fprintln(execution.Stdout, "undefined") @@ -357,6 +379,15 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { })) Expect(executions[1].Env).To(ContainElement(MatchRegexp(`^PATH=.*:node_modules/.bin$`))) Expect(executions[1].Dir).To(Equal(workingDir)) + Expect(buffer.String()).To(ContainLines( + " Running 'yarn config get yarn-offline-mirror'", + " stdout output", + " stderr output", + " undefined", + fmt.Sprintf(" Running 'yarn install --ignore-engines --frozen-lockfile --production false --modules-folder %s'", filepath.Join(modulesLayerPath, "node_modules")), + " stdout output", + " stderr output", + )) }) }) @@ -383,7 +414,15 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { })) Expect(executions[1].Env).To(ContainElement(MatchRegexp(`^PATH=.*:node_modules/.bin$`))) Expect(executions[1].Dir).To(Equal(workingDir)) - + Expect(buffer.String()).To(ContainLines( + " Running 'yarn config get yarn-offline-mirror'", + " stdout output", + " stderr output", + " undefined", + fmt.Sprintf(" Running 'yarn install --ignore-engines --frozen-lockfile --modules-folder %s'", filepath.Join(modulesLayerPath, "node_modules")), + " stdout output", + " stderr output", + )) }) }) @@ -427,6 +466,13 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { })) Expect(executions[1].Env).To(ContainElement(MatchRegexp(`^PATH=.*:node_modules/.bin$`))) Expect(executions[1].Dir).To(Equal(workingDir)) + Expect(buffer.String()).To(ContainLines( + " Running 'yarn config get yarn-offline-mirror'", + " warning some extraneous warning", + " warning some other warning", + fmt.Sprintf(" %s", filepath.Join(workingDir, "offline-mirror")), + fmt.Sprintf(" Running 'yarn install --ignore-engines --frozen-lockfile --offline --modules-folder %s'", filepath.Join(modulesLayerPath, "node_modules")), + )) }) }) @@ -447,9 +493,7 @@ func testInstallProcess(t *testing.T, context spec.G, it spec.S) { it("returns an error", func() { err := installProcess.Execute(workingDir, modulesLayerPath, true) Expect(err).To(MatchError(ContainSubstring("failed to execute yarn config"))) - Expect(err).To(MatchError(ContainSubstring("some stdout error"))) - Expect(err).To(MatchError(ContainSubstring("some stderr error"))) - Expect(err).To(MatchError(ContainSubstring("yarn config failed"))) + Expect(err).To(MatchError(ContainSubstring("error: yarn config failed"))) }) })