Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5e4391c

Browse files
az-wegiftAmadeusz Żołnowskiantonbabenko
authored
feat: Respect the package-lock.json for a NodeJS Lambda function (#681)
Co-authored-by: Amadeusz Żołnowski <amadeusz@runa.io> Co-authored-by: Anton Babenko <393243+antonbabenko@users.noreply.github.com>
1 parent a5433c0 commit 5e4391c

File tree

6 files changed

+205
-8
lines changed

6 files changed

+205
-8
lines changed

‎examples/build-package/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Note that this example may create resources which cost money. Run `terraform des
4545
| <a name="module_package_dir_poetry"></a> [package\_dir\_poetry](#module\_package\_dir\_poetry) | ../../ | n/a |
4646
| <a name="module_package_dir_poetry_no_docker"></a> [package\_dir\_poetry\_no\_docker](#module\_package\_dir\_poetry\_no\_docker) | ../../ | n/a |
4747
| <a name="module_package_dir_with_npm_install"></a> [package\_dir\_with\_npm\_install](#module\_package\_dir\_with\_npm\_install) | ../../ | n/a |
48+
| <a name="module_package_dir_with_npm_install_lock_file"></a> [package\_dir\_with\_npm\_install\_lock\_file](#module\_package\_dir\_with\_npm\_install\_lock\_file) | ../../ | n/a |
4849
| <a name="module_package_dir_without_npm_install"></a> [package\_dir\_without\_npm\_install](#module\_package\_dir\_without\_npm\_install) | ../../ | n/a |
4950
| <a name="module_package_dir_without_pip_install"></a> [package\_dir\_without\_pip\_install](#module\_package\_dir\_without\_pip\_install) | ../../ | n/a |
5051
| <a name="module_package_file"></a> [package\_file](#module\_package\_file) | ../../ | n/a |
@@ -53,6 +54,7 @@ Note that this example may create resources which cost money. Run `terraform des
5354
| <a name="module_package_src_poetry2"></a> [package\_src\_poetry2](#module\_package\_src\_poetry2) | ../../ | n/a |
5455
| <a name="module_package_with_commands_and_patterns"></a> [package\_with\_commands\_and\_patterns](#module\_package\_with\_commands\_and\_patterns) | ../../ | n/a |
5556
| <a name="module_package_with_docker"></a> [package\_with\_docker](#module\_package\_with\_docker) | ../../ | n/a |
57+
| <a name="module_package_with_npm_lock_in_docker"></a> [package\_with\_npm\_lock\_in\_docker](#module\_package\_with\_npm\_lock\_in\_docker) | ../../ | n/a |
5658
| <a name="module_package_with_npm_requirements_in_docker"></a> [package\_with\_npm\_requirements\_in\_docker](#module\_package\_with\_npm\_requirements\_in\_docker) | ../../ | n/a |
5759
| <a name="module_package_with_patterns"></a> [package\_with\_patterns](#module\_package\_with\_patterns) | ../../ | n/a |
5860
| <a name="module_package_with_pip_requirements_in_docker"></a> [package\_with\_pip\_requirements\_in\_docker](#module\_package\_with\_pip\_requirements\_in\_docker) | ../../ | n/a |

‎examples/build-package/main.tf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,18 @@ module "package_dir_with_npm_install" {
365365
source_path = "${path.module}/../fixtures/nodejs14.x-app1"
366366
}
367367

368+
# Create zip-archive of a single directory where "npm install" will also be
369+
# executed (default for nodejs runtime). This example has package-lock.json which
370+
# is respected when installing dependencies.
371+
module "package_dir_with_npm_install_lock_file" {
372+
source = "../../"
373+
374+
create_function = false
375+
376+
runtime = "nodejs14.x"
377+
source_path = "${path.module}/../fixtures/nodejs14.x-app2"
378+
}
379+
368380
# Create zip-archive of a single directory without running "npm install" (which is the default for nodejs runtime)
369381
module "package_dir_without_npm_install" {
370382
source = "../../"
@@ -393,6 +405,20 @@ module "package_with_npm_requirements_in_docker" {
393405
hash_extra = "something-unique-to-not-conflict-with-module.package_dir_with_npm_install"
394406
}
395407

408+
# Create zip-archive of a single directory where "npm install" will also be
409+
# executed using docker. This example has package-lock.json which is respected
410+
# when installing dependencies.
411+
module "package_with_npm_lock_in_docker" {
412+
source = "../../"
413+
414+
create_function = false
415+
416+
runtime = "nodejs14.x"
417+
source_path = "${path.module}/../fixtures/nodejs14.x-app2"
418+
build_in_docker = true
419+
hash_extra = "something-unique-to-not-conflict-with-module.package_dir_with_npm_install"
420+
}
421+
396422
################################
397423
# Build package in Docker and
398424
# use it to deploy Lambda Layer
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
module.exports.hello = async (event) => {
4+
console.log(event);
5+
return {
6+
statusCode: 200,
7+
body: JSON.stringify(
8+
{
9+
message: `Go Serverless.tf! Your Nodejs function executed successfully!`,
10+
input: event,
11+
},
12+
null,
13+
2
14+
),
15+
};
16+
};

‎examples/fixtures/nodejs14.x-app2/package-lock.json

Lines changed: 83 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "nodejs14.x-app1",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"dependencies": {
6+
"requests": "^0.2.0"
7+
}
8+
}

‎package.py

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,14 @@ def npm_requirements_step(path, prefix=None, required=False, tmp_dir=None):
733733
requirements = path
734734
if os.path.isdir(path):
735735
requirements = os.path.join(path, "package.json")
736+
npm_lock_file = os.path.join(path, "package-lock.json")
737+
else:
738+
npm_lock_file = os.path.join(os.path.dirname(path), "package-lock.json")
739+
740+
if os.path.isfile(npm_lock_file):
741+
hash(npm_lock_file)
742+
log.info("Added npm lock file: %s", npm_lock_file)
743+
736744
if not os.path.isfile(requirements):
737745
if required:
738746
raise RuntimeError("File not found: {}".format(requirements))
@@ -1088,7 +1096,7 @@ def install_pip_requirements(query, requirements_file, tmp_dir):
10881096
ok = True
10891097
elif docker_file or docker_build_root:
10901098
raise ValueError(
1091-
"docker_image must be specified ""for a custom image future references"
1099+
"docker_image must be specified for a custom image future references"
10921100
)
10931101

10941102
working_dir = os.getcwd()
@@ -1108,7 +1116,7 @@ def install_pip_requirements(query, requirements_file, tmp_dir):
11081116
elif OSX:
11091117
# Workaround for OSX when XCode command line tools'
11101118
# python becomes the main system python interpreter
1111-
os_path = "{}:/Library/Developer/CommandLineTools""/usr/bin".format(
1119+
os_path = "{}:/Library/Developer/CommandLineTools/usr/bin".format(
11121120
os.environ["PATH"]
11131121
)
11141122
subproc_env = os.environ.copy()
@@ -1390,14 +1398,15 @@ def install_npm_requirements(query, requirements_file, tmp_dir):
13901398
ok = True
13911399
elif docker_file or docker_build_root:
13921400
raise ValueError(
1393-
"docker_image must be specified ""for a custom image future references"
1401+
"docker_image must be specified for a custom image future references"
13941402
)
13951403

13961404
log.info("Installing npm requirements: %s", requirements_file)
13971405
with tempdir(tmp_dir) as temp_dir:
1398-
requirements_filename = os.path.basename(requirements_file)
1399-
target_file = os.path.join(temp_dir, requirements_filename)
1400-
shutil.copyfile(requirements_file, target_file)
1406+
temp_copy = TemporaryCopy(os.path.dirname(requirements_file), temp_dir, log)
1407+
temp_copy.add(os.path.basename(requirements_file))
1408+
temp_copy.add("package-lock.json", required=False)
1409+
temp_copy.copy_to_target_dir()
14011410

14021411
subproc_env = None
14031412
npm_exec = "npm"
@@ -1442,10 +1451,63 @@ def install_npm_requirements(query, requirements_file, tmp_dir):
14421451
"available in system PATH".format(runtime)
14431452
) from e
14441453

1445-
os.remove(target_file)
1454+
temp_copy.remove_from_target_dir()
14461455
yield temp_dir
14471456

14481457

1458+
class TemporaryCopy:
1459+
"""Temporarily copy files to a specified location and remove them when
1460+
not needed.
1461+
"""
1462+
1463+
def __init__(self, source_dir_path, target_dir_path, logger=None):
1464+
"""Initialise with a target and a source directories."""
1465+
self.source_dir_path = source_dir_path
1466+
self.target_dir_path = target_dir_path
1467+
self._filenames = []
1468+
self._logger = logger
1469+
1470+
def _make_source_path(self, filename):
1471+
return os.path.join(self.source_dir_path, filename)
1472+
1473+
def _make_target_path(self, filename):
1474+
return os.path.join(self.target_dir_path, filename)
1475+
1476+
def add(self, filename, *, required=True):
1477+
"""Add a file to be copied from from source to target directory
1478+
when `TemporaryCopy.copy_to_target_dir()` is called.
1479+
1480+
By default, the file must exist in the source directory. Set `required`
1481+
to `False` if the file is optional.
1482+
"""
1483+
if os.path.exists(self._make_source_path(filename)):
1484+
self._filenames.append(filename)
1485+
elif required:
1486+
raise RuntimeError("File not found: {}".format(filename))
1487+
1488+
def copy_to_target_dir(self):
1489+
"""Copy files (added so far) to the target directory."""
1490+
for filename in self._filenames:
1491+
if self._logger:
1492+
self._logger.info("Copying temporarily '%s'", filename)
1493+
1494+
shutil.copyfile(
1495+
self._make_source_path(filename),
1496+
self._make_target_path(filename),
1497+
)
1498+
1499+
def remove_from_target_dir(self):
1500+
"""Remove files (added so far) from the target directory."""
1501+
for filename in self._filenames:
1502+
if self._logger:
1503+
self._logger.info("Removing temporarily copied '%s'", filename)
1504+
1505+
try:
1506+
os.remove(self._make_target_path(filename))
1507+
except FileNotFoundError:
1508+
pass
1509+
1510+
14491511
def docker_image_id_command(tag):
14501512
""""""
14511513
docker_cmd = ["docker", "images", "--format={{.ID}}", tag]
@@ -1649,7 +1711,7 @@ def prepare_command(args):
16491711
timestamp = timestamp_now_ns()
16501712
was_missing = True
16511713
else:
1652-
timestamp = "<WARNING: Missing lambda zip artifacts ""wouldn't be restored>"
1714+
timestamp = "<WARNING: Missing lambda zip artifacts wouldn't be restored>"
16531715

16541716
# Replace variables in the build command with calculated values.
16551717
build_data = {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /