diff --git a/aws_lambda_builders/workflows/go_modules/builder.py b/aws_lambda_builders/workflows/go_modules/builder.py index 22d51b4e8..d2fc048e9 100644 --- a/aws_lambda_builders/workflows/go_modules/builder.py +++ b/aws_lambda_builders/workflows/go_modules/builder.py @@ -2,6 +2,7 @@ Build a Go project using standard Go tooling """ import logging +from pathlib import Path from aws_lambda_builders.workflow import BuildMode from aws_lambda_builders.architecture import X86_64, ARM64 @@ -21,7 +22,7 @@ class GoModulesBuilder(object): LANGUAGE = "go" - def __init__(self, osutils, binaries, mode=BuildMode.RELEASE, architecture=X86_64, trim_go_path=False): + def __init__(self, osutils, binaries, handler, mode=BuildMode.RELEASE, architecture=X86_64, trim_go_path=False): """Initialize a GoModulesBuilder. :type osutils: :class:`lambda_builders.utils.OSUtils` @@ -42,6 +43,7 @@ def __init__(self, osutils, binaries, mode=BuildMode.RELEASE, architecture=X86_6 self.mode = mode self.goarch = get_goarch(architecture) self.trim_go_path = trim_go_path + self.handler = handler def build(self, source_dir_path, output_path): """Builds a go project onto an output path. @@ -69,6 +71,35 @@ def build(self, source_dir_path, output_path): out, err = p.communicate() if p.returncode != 0: - raise BuilderError(message=err.decode("utf8").strip()) + LOG.debug(err.decode("utf8").strip()) + LOG.debug("Go files not found. Attempting to build for Go files in a different directory") + process, p_out, p_err = self._attempt_to_build_from_handler(cmd, source_dir_path, env) + if process.returncode != 0: + raise BuilderError(message=p_err.decode("utf8").strip()) + return p_out.decode("utf8").strip() return out.decode("utf8").strip() + + def _attempt_to_build_from_handler(self, cmd: list, source_dir_path: str, env: dict): + """Builds Go files when package/source file in different directory + + :type cmd: list + :param cmd: list of commands. + + :type source_dir_path: str + :param source_dir_path: path to the source file/package. + + :type env: dict + :param env: dictionary with environment variables. + """ + + # Path to the source directory for Go files in a diff directory + cmd[-1] = str(Path(source_dir_path, self.handler)) + LOG.debug( + "Go files not found at CodeUri %s . Descending into sub-directories to find the handler: %s", + source_dir_path, + cmd[-1], + ) + p = self.osutils.popen(cmd, cwd=source_dir_path, env=env, stdout=self.osutils.pipe, stderr=self.osutils.pipe) + out, err = p.communicate() + return p, out, err diff --git a/aws_lambda_builders/workflows/go_modules/workflow.py b/aws_lambda_builders/workflows/go_modules/workflow.py index fa780a5ad..94f3900d0 100644 --- a/aws_lambda_builders/workflows/go_modules/workflow.py +++ b/aws_lambda_builders/workflows/go_modules/workflow.py @@ -33,8 +33,14 @@ def __init__( output_path = osutils.joinpath(artifacts_dir, handler) builder = GoModulesBuilder( - osutils, binaries=self.binaries, mode=mode, architecture=self.architecture, trim_go_path=trim_go_path + osutils, + binaries=self.binaries, + handler=handler, + mode=mode, + architecture=self.architecture, + trim_go_path=trim_go_path, ) + self.actions = [GoModulesBuildAction(source_dir, output_path, builder)] def get_validators(self): diff --git a/tests/integration/workflows/go_modules/test_go.py b/tests/integration/workflows/go_modules/test_go.py index 64ff05d49..3027cae24 100644 --- a/tests/integration/workflows/go_modules/test_go.py +++ b/tests/integration/workflows/go_modules/test_go.py @@ -181,3 +181,18 @@ def test_builds_with_trimpath_are_equal(self): pathname = Path(self.artifacts_dir, "no-deps-main") pathnameOfCopy = Path(self.artifacts_dir, "no-deps-main-copy") self.assertEqual(get_md5_hexdigest(pathname), get_md5_hexdigest(pathnameOfCopy)) + + def test_builds_project_with_nested_dir(self): + source_dir = os.path.join(self.TEST_DATA_FOLDER, "nested_build_folder") + package_dir = os.path.join(source_dir, "cmd/helloWorld") + self.builder.build( + package_dir, + self.artifacts_dir, + self.scratch_dir, + os.path.join(source_dir, "go.mod"), + runtime=self.runtime, + options={"artifact_executable_name": "helloWorld"}, + ) + expected_files = {"helloWorld"} + output_files = set(os.listdir(self.artifacts_dir)) + self.assertEqual(expected_files, output_files) diff --git a/tests/integration/workflows/go_modules/testdata/nested_build_folder/cmd/helloWorld/main.go b/tests/integration/workflows/go_modules/testdata/nested_build_folder/cmd/helloWorld/main.go new file mode 100644 index 000000000..790580777 --- /dev/null +++ b/tests/integration/workflows/go_modules/testdata/nested_build_folder/cmd/helloWorld/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + +} diff --git a/tests/integration/workflows/go_modules/testdata/nested_build_folder/go.mod b/tests/integration/workflows/go_modules/testdata/nested_build_folder/go.mod new file mode 100644 index 000000000..dfce2c45b --- /dev/null +++ b/tests/integration/workflows/go_modules/testdata/nested_build_folder/go.mod @@ -0,0 +1 @@ +module github.com/awslabs/aws-lambda-builders \ No newline at end of file diff --git a/tests/integration/workflows/go_modules/testdata/nested_build_folder/go.sum b/tests/integration/workflows/go_modules/testdata/nested_build_folder/go.sum new file mode 100644 index 000000000..907f238ae --- /dev/null +++ b/tests/integration/workflows/go_modules/testdata/nested_build_folder/go.sum @@ -0,0 +1,10 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aws/aws-lambda-go v1.8.0 h1:YMCzi9FP7MNVVj9AkGpYyaqh/mvFOjhqiDtnNlWtKTg= +github.com/aws/aws-lambda-go v1.8.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= \ No newline at end of file diff --git a/tests/unit/workflows/go_modules/test_builder.py b/tests/unit/workflows/go_modules/test_builder.py index d821a4a74..6af448030 100644 --- a/tests/unit/workflows/go_modules/test_builder.py +++ b/tests/unit/workflows/go_modules/test_builder.py @@ -1,6 +1,7 @@ from unittest import TestCase from mock import patch, Mock +from pathlib import Path from aws_lambda_builders.binary_path import BinaryPath from aws_lambda_builders.workflows.go_modules.builder import GoModulesBuilder, BuilderError @@ -21,14 +22,16 @@ class TestGoBuilder(TestCase): def setUp(self, OSUtilMock): self.osutils = OSUtilMock.return_value self.osutils.pipe = "PIPE" + self.handler = "cmd/helloWorld" self.popen = FakePopen() - self.osutils.popen.side_effect = [self.popen] + self.popen_go_case = FakePopen() + self.osutils.popen.side_effect = [self.popen, self.popen_go_case] self.binaries = {"go": BinaryPath(resolver=Mock(), validator=Mock(), binary="go", binary_path="/path/to/go")} - self.under_test = GoModulesBuilder(self.osutils, self.binaries) + self.under_test = GoModulesBuilder(self.osutils, self.binaries, self.handler) def test_run_executes_bundler_on_nixes(self): self.osutils.is_windows.side_effect = [False] - self.under_test = GoModulesBuilder(self.osutils, self.binaries) + self.under_test = GoModulesBuilder(self.osutils, self.binaries, self.handler) self.under_test.build("source_dir", "output_path") self.osutils.popen.assert_called_with( ["/path/to/go", "build", "-o", "output_path", "source_dir"], @@ -38,12 +41,29 @@ def test_run_executes_bundler_on_nixes(self): stdout="PIPE", ) + def test_build_gofiles_in_different_directory(self): + self.popen.returncode = 1 + self.popen_go_case.returncode = 0 + self.osutils.is_windows.side_effect = [False] + self.under_test = GoModulesBuilder(self.osutils, self.binaries, self.handler) + self.under_test.build("source_dir_path", "output_path") + + self.osutils.popen.assert_called_with( + ["/path/to/go", "build", "-o", "output_path", str(Path("source_dir_path/cmd/helloWorld"))], + cwd="source_dir_path", + env={"GOOS": "linux", "GOARCH": "amd64"}, + stderr="PIPE", + stdout="PIPE", + ) + def test_returns_popen_out_decoded_if_retcode_is_0(self): self.popen.out = b"some encoded text\n\n" result = self.under_test.build("source_dir", "output_path") self.assertEqual(result, "some encoded text") - def test_raises_BuilderError_with_err_text_if_retcode_is_not_0(self): + @patch("aws_lambda_builders.workflows.go_modules.builder.GoModulesBuilder._attempt_to_build_from_handler") + def test_raises_BuilderError_with_err_text_if_retcode_is_not_0(self, patched_helper): + patched_helper.return_value = self.popen, "", b"some error text\n\n" self.popen.returncode = 1 self.popen.err = b"some error text\n\n" with self.assertRaises(BuilderError) as raised: @@ -51,7 +71,7 @@ def test_raises_BuilderError_with_err_text_if_retcode_is_not_0(self): self.assertEqual(raised.exception.args[0], "Builder Failed: some error text") def test_debug_configuration_set(self): - self.under_test = GoModulesBuilder(self.osutils, self.binaries, "Debug") + self.under_test = GoModulesBuilder(self.osutils, self.binaries, self.handler, "Debug") self.under_test.build("source_dir", "output_path") self.osutils.popen.assert_called_with( ["/path/to/go", "build", "-gcflags", "all=-N -l", "-o", "output_path", "source_dir"], @@ -62,7 +82,7 @@ def test_debug_configuration_set(self): ) def test_trimpath_configuration_set(self): - self.under_test = GoModulesBuilder(self.osutils, self.binaries, "release", "x86_64", True) + self.under_test = GoModulesBuilder(self.osutils, self.binaries, self.handler, "release", "x86_64", True) self.under_test.build("source_dir", "output_path") self.osutils.popen.assert_called_with( ["/path/to/go", "build", "-trimpath", "-o", "output_path", "source_dir"], @@ -73,7 +93,7 @@ def test_trimpath_configuration_set(self): ) def test_debug_configuration_set_with_arm_architecture(self): - self.under_test = GoModulesBuilder(self.osutils, self.binaries, "Debug", "arm64") + self.under_test = GoModulesBuilder(self.osutils, self.binaries, self.handler, "Debug", "arm64") self.under_test.build("source_dir", "output_path") self.osutils.popen.assert_called_with( ["/path/to/go", "build", "-gcflags", "all=-N -l", "-o", "output_path", "source_dir"],