Skip to content

Commit 80831cc

Browse files
authored
Merge branch 'develop' into rust-cargo-lambda-workflow
2 parents 6c55ba9 + 23b71aa commit 80831cc

File tree

12 files changed

+173
-39
lines changed

12 files changed

+173
-39
lines changed

.github/ISSUE_TEMPLATE.md

Lines changed: 0 additions & 14 deletions
This file was deleted.

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
name: Bug report
3+
about: Create an issue to report a bug for AWS Lambda Builders
4+
title: "Bug: TITLE"
5+
labels: ['type/bug', 'stage/needs-triage']
6+
assignees: ''
7+
8+
---
9+
10+
<!-- Make sure we don't have an existing Issue that reports the bug you are seeing (both open and closed).
11+
If you do find an existing Issue, re-open or add a comment to that Issue instead of creating a new one. -->
12+
13+
### Description:
14+
<!-- Briefly describe the bug you are facing.-->
15+
16+
17+
18+
### Steps to reproduce:
19+
<!-- Provide detailed steps to replicate the bug, including steps from third party tools (CDK, etc.) -->
20+
21+
22+
23+
### Observed result:
24+
<!-- Please provide command output with `--debug` flag set.-->
25+
26+
27+
28+
### Expected result:
29+
<!-- Describe what you expected.-->
30+
31+
32+
33+
### Additional environment details (Ex: Windows, Mac, Amazon Linux etc)
34+
35+
1. OS:
36+
2. If using SAM CLI, `sam --version`:
37+
3. AWS region:
38+
39+
`Add --debug flag to any SAM CLI commands you are running`

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
blank_issues_enabled: false
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea/feature/enhancement for AWS Lambda Builders
4+
title: "Feature request: TITLE"
5+
labels: ['type/feature', 'stage/needs-triage']
6+
assignees: ''
7+
8+
---
9+
10+
<!-- Make sure we don't have an existing Issue for that feature request (open or closed). -->
11+
12+
### Describe your idea/feature/enhancement
13+
14+
Provide a clear description.
15+
16+
Ex: I wish the AWS Lambda Builders would [...]
17+
18+
### Proposal
19+
20+
Add details on how to add this to the product.
21+
22+
### Additional Details

.github/ISSUE_TEMPLATE/other.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
name: Other
3+
about: Choose if your issue doesn't apply to the other templates
4+
title: ''
5+
labels: ['stage/needs-triage']
6+
assignees: ''
7+
8+
---

.github/workflows/pr-labeler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ jobs:
3434
issue_number: context.issue.number,
3535
owner: context.repo.owner,
3636
repo: context.repo.repo,
37-
labels: ['pr/external']
37+
labels: ['pr/external', 'stage/needs-triage']
3838
})
3939
}

aws_lambda_builders/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
22
AWS Lambda Builder Library
33
"""
4-
__version__ = "1.16.0"
4+
__version__ = "1.18.0"
55
RPC_PROTOCOL_VERSION = "0.3"

aws_lambda_builders/actions.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
import os
77
import shutil
8-
import six
8+
from typing import Set, Iterator, Tuple
99

1010
from aws_lambda_builders.utils import copytree
1111

@@ -58,7 +58,7 @@ def __new__(mcs, name, bases, class_dict):
5858

5959
# Validate class variables
6060
# All classes must provide a name
61-
if not isinstance(cls.NAME, six.string_types):
61+
if not isinstance(cls.NAME, str):
6262
raise ValueError("Action must provide a valid name")
6363

6464
if not Purpose.has_value(cls.PURPOSE):
@@ -67,7 +67,7 @@ def __new__(mcs, name, bases, class_dict):
6767
return cls
6868

6969

70-
class BaseAction(six.with_metaclass(_ActionMetaClass, object)):
70+
class BaseAction(object, metaclass=_ActionMetaClass):
7171
"""
7272
Base class for all actions. It does not provide any implementation.
7373
"""
@@ -125,14 +125,9 @@ def __init__(self, source_dir, artifact_dir, destination_dir):
125125
self.dest_dir = destination_dir
126126

127127
def execute(self):
128-
source = set(os.listdir(self.source_dir))
129-
artifact = set(os.listdir(self.artifact_dir))
130-
dependencies = artifact - source
131-
132-
for name in dependencies:
133-
dependencies_source = os.path.join(self.artifact_dir, name)
134-
new_destination = os.path.join(self.dest_dir, name)
128+
deps_manager = DependencyManager(self.source_dir, self.artifact_dir, self.dest_dir)
135129

130+
for dependencies_source, new_destination in deps_manager.yield_source_dest():
136131
if os.path.isdir(dependencies_source):
137132
copytree(dependencies_source, new_destination)
138133
else:
@@ -154,14 +149,9 @@ def __init__(self, source_dir, artifact_dir, destination_dir):
154149
self.dest_dir = destination_dir
155150

156151
def execute(self):
157-
source = set(os.listdir(self.source_dir))
158-
artifact = set(os.listdir(self.artifact_dir))
159-
dependencies = artifact - source
160-
161-
for name in dependencies:
162-
dependencies_source = os.path.join(self.artifact_dir, name)
163-
new_destination = os.path.join(self.dest_dir, name)
152+
deps_manager = DependencyManager(self.source_dir, self.artifact_dir, self.dest_dir)
164153

154+
for dependencies_source, new_destination in deps_manager.yield_source_dest():
165155
# shutil.move can't create subfolders if this is the first file in that folder
166156
if os.path.isfile(dependencies_source):
167157
os.makedirs(os.path.dirname(new_destination), exist_ok=True)
@@ -198,3 +188,36 @@ def execute(self):
198188
shutil.rmtree(target_path)
199189
else:
200190
os.remove(target_path)
191+
192+
193+
class DependencyManager:
194+
"""
195+
Class for handling the management of dependencies between directories
196+
"""
197+
198+
# Ignore these files when comparing against which dependencies to move
199+
# This allows for the installation of dependencies in the source directory
200+
IGNORE_LIST = ["node_modules"]
201+
202+
def __init__(self, source_dir, artifact_dir, destination_dir) -> None:
203+
self._source_dir: str = source_dir
204+
self._artifact_dir: str = artifact_dir
205+
self._dest_dir: str = destination_dir
206+
self._dependencies: Set[str] = set()
207+
208+
def yield_source_dest(self) -> Iterator[Tuple[str, str]]:
209+
self._set_dependencies()
210+
for dep in self._dependencies:
211+
yield os.path.join(self._artifact_dir, dep), os.path.join(self._dest_dir, dep)
212+
213+
def _set_dependencies(self) -> None:
214+
source = self._get_source_files_exclude_deps()
215+
artifact = set(os.listdir(self._artifact_dir))
216+
self._dependencies = artifact - source
217+
218+
def _get_source_files_exclude_deps(self) -> Set[str]:
219+
source_files = set(os.listdir(self._source_dir))
220+
for item in self.IGNORE_LIST:
221+
if item in source_files:
222+
source_files.remove(item)
223+
return source_files

aws_lambda_builders/workflow.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import logging
77

88
from collections import namedtuple
9-
import six
109

1110
from aws_lambda_builders.binary_path import BinaryPath
1211
from aws_lambda_builders.path_resolver import PathResolver
@@ -118,7 +117,7 @@ def __new__(mcs, name, bases, class_dict):
118117
# Validate class variables
119118

120119
# All classes must provide a name
121-
if not isinstance(cls.NAME, six.string_types):
120+
if not isinstance(cls.NAME, str):
122121
raise ValueError("Workflow must provide a valid name")
123122

124123
# All workflows must express their capabilities
@@ -131,7 +130,7 @@ def __new__(mcs, name, bases, class_dict):
131130
return cls
132131

133132

134-
class BaseWorkflow(six.with_metaclass(_WorkflowMetaClass, object)):
133+
class BaseWorkflow(object, metaclass=_WorkflowMetaClass):
135134
"""
136135
Default implementation of the builder workflow. It provides several useful capabilities out-of-box that help
137136
minimize the scope of build actions.

requirements/base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
six~=1.11
1+

tests/integration/workflows/python_pip/test_python_pip.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,15 @@ def test_mismatch_runtime_python_project(self):
137137
runtime=self.runtime_mismatch[self.runtime],
138138
)
139139
except WorkflowFailedError as ex:
140-
self.assertIn("Binary validation failed", str(ex))
140+
# handle both e.g. missing /usr/bin/python2.7 and situation where
141+
# python2.7 does not have pip installed (as is the case in some
142+
# Mac environments)
143+
ex_s = str(ex)
144+
if (
145+
"Binary validation failed" not in ex_s
146+
and "pip executable not found in your python environment" not in ex_s
147+
):
148+
raise AssertionError("Unexpected exception") from ex
141149

142150
def test_runtime_validate_python_project_fail_open_unsupported_runtime(self):
143151
with self.assertRaises(WorkflowFailedError):

tests/unit/test_actions.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
from pathlib import Path
2+
from typing import List, Tuple
13
from unittest import TestCase
2-
from mock import patch, ANY
4+
from mock import patch, ANY, Mock
5+
from parameterized import parameterized
36

47
from aws_lambda_builders.actions import (
58
BaseAction,
@@ -8,6 +11,7 @@
811
CopyDependenciesAction,
912
MoveDependenciesAction,
1013
CleanUpAction,
14+
DependencyManager,
1115
)
1216

1317

@@ -128,3 +132,47 @@ def test_must_copy(self, path_mock, listdir_mock, isdir_mock, rmtree_mock, rm_mo
128132
listdir_mock.assert_any_call(target_dir)
129133
rmtree_mock.assert_any_call("dir")
130134
rm_mock.assert_any_call("file")
135+
136+
137+
class TestDependencyManager(TestCase):
138+
@parameterized.expand(
139+
[
140+
(
141+
["app.js", "package.js", "libs", "node_modules"],
142+
["app.js", "package.js", "libs", "node_modules"],
143+
[("artifacts/node_modules", "dest/node_modules")],
144+
None,
145+
),
146+
(
147+
["file1, file2", "dep1", "dep2"],
148+
["file1, file2", "dep1", "dep2"],
149+
[("artifacts/dep1", "dest/dep1"), ("artifacts/dep2", "dest/dep2")],
150+
["dep1", "dep2"],
151+
),
152+
(
153+
["file1, file2"],
154+
["file1, file2", "dep1", "dep2"],
155+
[("artifacts/dep1", "dest/dep1"), ("artifacts/dep2", "dest/dep2")],
156+
["dep1", "dep2"],
157+
),
158+
]
159+
)
160+
@patch("aws_lambda_builders.actions.os.listdir")
161+
def test_excludes_dependencies_from_source(
162+
self, source_files, artifact_files, expected, mock_dependencies, patched_list_dir
163+
):
164+
dependency_manager = DependencyManager("source", "artifacts", "dest")
165+
dependency_manager.IGNORE_LIST = (
166+
dependency_manager.IGNORE_LIST if mock_dependencies is None else mock_dependencies
167+
)
168+
patched_list_dir.side_effect = [source_files, artifact_files]
169+
source_destinations = list(
170+
TestDependencyManager._convert_strings_to_paths(list(dependency_manager.yield_source_dest()))
171+
)
172+
expected_paths = TestDependencyManager._convert_strings_to_paths(expected)
173+
for expected_source_dest in expected_paths:
174+
self.assertIn(expected_source_dest, source_destinations)
175+
176+
@staticmethod
177+
def _convert_strings_to_paths(source_dest_list):
178+
return map(lambda item: (Path(item[0]), Path(item[1])), source_dest_list)

0 commit comments

Comments
 (0)