Skip to content

Commit 67f60da

Browse files
authored
Merge pull request #212 from ligangty/cf
[Cherry-pick from 1.2.x] Fix wrong picking of the npm package.json
2 parents 65c0f61 + 83aa6b4 commit 67f60da

File tree

6 files changed

+193
-33
lines changed

6 files changed

+193
-33
lines changed

charon/pkgs/npm.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ def default(self, o):
7878
def handle_npm_uploading(
7979
tarball_path: str,
8080
product: str,
81-
buckets: List[Tuple[str, str, str, str]] = None,
81+
buckets: List[Tuple[str, str, str, str]],
8282
aws_profile=None,
8383
dir_=None,
84+
root_path="package",
8485
do_index=True,
8586
gen_sign=False,
8687
cf_enable=False,
@@ -115,7 +116,7 @@ def handle_npm_uploading(
115116
prefix = remove_prefix(bucket[2], "/")
116117
registry = bucket[3]
117118
target_dir, valid_paths, package_metadata = _scan_metadata_paths_from_archive(
118-
tarball_path, registry, prod=product, dir__=root_dir
119+
tarball_path, registry, prod=product, dir__=dir_, pkg_root=root_path
119120
)
120121
if not os.path.isdir(target_dir):
121122
logger.error("Error: the extracted target_dir path %s does not exist.", target_dir)
@@ -255,9 +256,10 @@ def handle_npm_uploading(
255256
def handle_npm_del(
256257
tarball_path: str,
257258
product: str,
258-
buckets: List[Tuple[str, str, str, str]] = None,
259+
buckets: List[Tuple[str, str, str, str]],
259260
aws_profile=None,
260261
dir_=None,
262+
root_path="package",
261263
do_index=True,
262264
cf_enable=False,
263265
dry_run=False,
@@ -276,7 +278,7 @@ def handle_npm_del(
276278
Returns the directory used for archive processing and if the rollback is successful
277279
"""
278280
target_dir, package_name_path, valid_paths = _scan_paths_from_archive(
279-
tarball_path, prod=product, dir__=dir_
281+
tarball_path, prod=product, dir__=dir_, pkg_root=root_path
280282
)
281283

282284
valid_dirs = __get_path_tree(valid_paths, target_dir)
@@ -474,11 +476,15 @@ def _gen_npm_package_metadata_for_del(
474476
return meta_files
475477

476478

477-
def _scan_metadata_paths_from_archive(path: str, registry: str, prod="", dir__=None) ->\
478-
Tuple[str, list, NPMPackageMetadata]:
479+
def _scan_metadata_paths_from_archive(
480+
path: str, registry: str, prod="", dir__=None, pkg_root="pakage"
481+
) -> Tuple[str, list, NPMPackageMetadata]:
479482
tmp_root = mkdtemp(prefix=f"npm-charon-{prod}-", dir=dir__)
480483
try:
481-
_, valid_paths = extract_npm_tarball(path, tmp_root, True, registry)
484+
_, valid_paths = extract_npm_tarball(
485+
path=path, target_dir=tmp_root, is_for_upload=True,
486+
pkg_root=pkg_root, registry=registry
487+
)
482488
if len(valid_paths) > 1:
483489
version = _scan_for_version(valid_paths[1])
484490
package = NPMPackageMetadata(version, True)
@@ -488,9 +494,13 @@ def _scan_metadata_paths_from_archive(path: str, registry: str, prod="", dir__=N
488494
sys.exit(1)
489495

490496

491-
def _scan_paths_from_archive(path: str, prod="", dir__=None) -> Tuple[str, str, list]:
497+
def _scan_paths_from_archive(
498+
path: str, prod="", dir__=None, pkg_root="package"
499+
) -> Tuple[str, str, list]:
492500
tmp_root = mkdtemp(prefix=f"npm-charon-{prod}-", dir=dir__)
493-
package_name_path, valid_paths = extract_npm_tarball(path, tmp_root, False)
501+
package_name_path, valid_paths = extract_npm_tarball(
502+
path=path, target_dir=tmp_root, is_for_upload=False, pkg_root=pkg_root
503+
)
494504
return tmp_root, package_name_path, valid_paths
495505

496506

charon/utils/archive.py

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ def extract_zip_with_files(zf: ZipFile, target_dir: str, file_suffix: str, debug
4646
zf.extractall(target_dir, members=filtered)
4747

4848

49-
def extract_npm_tarball(path: str, target_dir: str, is_for_upload: bool, registry=DEFAULT_REGISTRY)\
50-
-> Tuple[str, list]:
49+
def extract_npm_tarball(
50+
path: str, target_dir: str, is_for_upload: bool, pkg_root="package", registry=DEFAULT_REGISTRY
51+
) -> Tuple[str, list]:
5152
""" Extract npm tarball will relocate the tgz file and metadata files.
5253
* Locate tar path ( e.g.: jquery/-/jquery-7.6.1.tgz or @types/jquery/-/jquery-2.2.3.tgz).
5354
* Locate version metadata path (e.g.: jquery/7.6.1 or @types/jquery/2.2.3).
@@ -56,30 +57,50 @@ def extract_npm_tarball(path: str, target_dir: str, is_for_upload: bool, registr
5657
valid_paths = []
5758
package_name_path = str()
5859
tgz = tarfile.open(path)
60+
pkg_file = None
61+
root_pkg_file_exists = True
62+
try:
63+
root_pkg_path = os.path.join(pkg_root, "package.json")
64+
logger.debug(root_pkg_path)
65+
pkg_file = tgz.getmember(root_pkg_path)
66+
root_pkg_file_exists = pkg_file.isfile()
67+
except KeyError:
68+
root_pkg_file_exists = False
69+
pkg_file = None
5970
tgz.extractall()
60-
for f in tgz:
61-
if f.name.endswith("package.json"):
62-
version_data, parse_paths = __parse_npm_package_version_paths(f.path)
63-
package_name_path = parse_paths[0]
64-
os.makedirs(os.path.join(target_dir, parse_paths[0]))
65-
tarball_parent_path = os.path.join(target_dir, parse_paths[0], "-")
66-
valid_paths.append(os.path.join(tarball_parent_path, _get_tgz_name(path)))
67-
version_metadata_parent_path = os.path.join(
68-
target_dir, parse_paths[0], parse_paths[1]
71+
if not root_pkg_file_exists:
72+
logger.info(
73+
"Root package.json is not found for archive: %s, will search others",
74+
path
75+
)
76+
for f in tgz:
77+
if f.name.endswith("package.json"):
78+
logger.info("Found package.json as %s", f.path)
79+
pkg_file = f
80+
break
81+
if pkg_file:
82+
version_data, parse_paths = __parse_npm_package_version_paths(pkg_file.path)
83+
package_name_path = parse_paths[0]
84+
os.makedirs(os.path.join(target_dir, parse_paths[0]))
85+
tarball_parent_path = os.path.join(target_dir, parse_paths[0], "-")
86+
valid_paths.append(os.path.join(tarball_parent_path, _get_tgz_name(path)))
87+
version_metadata_parent_path = os.path.join(
88+
target_dir, parse_paths[0], parse_paths[1]
89+
)
90+
valid_paths.append(os.path.join(version_metadata_parent_path, "package.json"))
91+
92+
if is_for_upload:
93+
tgz_relative_path = "/".join([parse_paths[0], "-", _get_tgz_name(path)])
94+
__write_npm_version_dist(
95+
path, pkg_file.path, version_data, tgz_relative_path, registry
6996
)
70-
valid_paths.append(os.path.join(version_metadata_parent_path, "package.json"))
71-
72-
if is_for_upload:
73-
tgz_relative_path = "/".join([parse_paths[0], "-", _get_tgz_name(path)])
74-
__write_npm_version_dist(path, f.path, version_data, tgz_relative_path, registry)
75-
76-
os.makedirs(tarball_parent_path)
77-
target = os.path.join(tarball_parent_path, os.path.basename(path))
78-
shutil.copyfile(path, target)
79-
os.makedirs(version_metadata_parent_path)
80-
target = os.path.join(version_metadata_parent_path, os.path.basename(f.path))
81-
shutil.copyfile(f.path, target)
82-
break
97+
98+
os.makedirs(tarball_parent_path)
99+
target = os.path.join(tarball_parent_path, os.path.basename(path))
100+
shutil.copyfile(path, target)
101+
os.makedirs(version_metadata_parent_path)
102+
target = os.path.join(version_metadata_parent_path, os.path.basename(pkg_file.path))
103+
shutil.copyfile(pkg_file.path, target)
83104
return package_name_path, valid_paths
84105

85106

tests/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""
2+
Copyright (C) 2022 Red Hat, Inc. (https://github.com/Commonjava/charon)
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
"""
16+
17+
import logging
18+
19+
logging.basicConfig(level=logging.INFO)
20+
logging.getLogger("charon").setLevel(logging.DEBUG)
2.97 KB
Binary file not shown.
2.93 KB
Binary file not shown.

tests/test_npm_upload_diff_pkgs.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Copyright (C) 2022 Red Hat, Inc. (https://github.com/Commonjava/charon)
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
"""
16+
import os
17+
18+
from moto import mock_aws
19+
20+
from charon.pkgs.npm import handle_npm_uploading
21+
from charon.constants import DEFAULT_REGISTRY
22+
from tests.base import PackageBaseTest
23+
from tests.commons import TEST_BUCKET
24+
from tests.constants import INPUTS
25+
import logging
26+
27+
logger = logging.getLogger(f"charon.tests.{__name__}")
28+
29+
CODE_FRAME_FILES_REDHAT = [
30+
"@redhat/code-frame/7.14.5/package.json",
31+
"@redhat/code-frame/-/code-frame-7.14.5-multi-pkgs.tgz"
32+
]
33+
34+
CODE_FRAME_META_REDHAT = "@redhat/code-frame/package.json"
35+
36+
CODE_FRAME_FILES_BABEL = [
37+
"@babel/code-frame/7.14.5/package.json",
38+
"@babel/code-frame/-/code-frame-7.14.5-no-root-pkg.tgz"
39+
]
40+
41+
CODE_FRAME_META_BABEL = "@babel/code-frame/package.json"
42+
43+
44+
@mock_aws
45+
class NPMUploadTest(PackageBaseTest):
46+
47+
def test_npm_uploads_multi_pkgjson_with_root(self):
48+
test_tgz = os.path.join(INPUTS, "code-frame-7.14.5-multi-pkgs.tgz")
49+
product_7_14_5 = "code-frame-7.14.5"
50+
handle_npm_uploading(
51+
test_tgz, product_7_14_5,
52+
buckets=[('', TEST_BUCKET, '', DEFAULT_REGISTRY)],
53+
dir_=self.tempdir, do_index=False
54+
)
55+
test_bucket = self.mock_s3.Bucket(TEST_BUCKET)
56+
objs = list(test_bucket.objects.all())
57+
actual_files = [obj.key for obj in objs]
58+
logger.debug("actual_files: %s", actual_files)
59+
self.assertEqual(5, len(actual_files))
60+
61+
for f in CODE_FRAME_FILES_REDHAT:
62+
self.assertIn(f, actual_files)
63+
self.check_product(f, [product_7_14_5])
64+
self.assertIn(CODE_FRAME_META_REDHAT, actual_files)
65+
66+
meta_obj_client = test_bucket.Object(CODE_FRAME_META_REDHAT)
67+
meta_content_client = str(meta_obj_client.get()["Body"].read(), "utf-8")
68+
self.assertIn("\"name\": \"@redhat/code-frame\"", meta_content_client)
69+
self.assertIn("\"description\": \"Generate errors that contain a code frame that point to "
70+
"source locations.\"", meta_content_client)
71+
self.assertIn("\"repository\": {\"type\": \"git\", \"url\": "
72+
"\"https://github.com/babel/babel.git\"", meta_content_client)
73+
self.assertIn("\"version\": \"7.14.5\"", meta_content_client)
74+
self.assertIn("\"versions\": {", meta_content_client)
75+
self.assertIn("\"7.14.5\": {\"name\":", meta_content_client)
76+
self.assertIn("\"license\": \"MIT\"", meta_content_client)
77+
self.assertNotIn("\"dist_tags\":", meta_content_client)
78+
79+
def test_npm_uploads_multi_pkgjson_with_no_root(self):
80+
test_tgz = os.path.join(INPUTS, "code-frame-7.14.5-no-root-pkg.tgz")
81+
product_7_14_5 = "code-frame-7.14.5"
82+
handle_npm_uploading(
83+
test_tgz, product_7_14_5,
84+
buckets=[('', TEST_BUCKET, '', DEFAULT_REGISTRY)],
85+
dir_=self.tempdir, do_index=False
86+
)
87+
test_bucket = self.mock_s3.Bucket(TEST_BUCKET)
88+
objs = list(test_bucket.objects.all())
89+
actual_files = [obj.key for obj in objs]
90+
logger.debug("actual_files: %s", actual_files)
91+
self.assertEqual(5, len(actual_files))
92+
93+
for f in CODE_FRAME_FILES_BABEL:
94+
self.assertIn(f, actual_files)
95+
self.check_product(f, [product_7_14_5])
96+
self.assertIn(CODE_FRAME_META_BABEL, actual_files)
97+
98+
meta_obj_client = test_bucket.Object(CODE_FRAME_META_BABEL)
99+
meta_content_client = str(meta_obj_client.get()["Body"].read(), "utf-8")
100+
self.assertIn("\"name\": \"@babel/code-frame\"", meta_content_client)
101+
self.assertIn("\"description\": \"Generate errors that contain a code frame that point to "
102+
"source locations.\"", meta_content_client)
103+
self.assertIn("\"repository\": {\"type\": \"git\", \"url\": "
104+
"\"https://github.com/babel/babel.git\"", meta_content_client)
105+
self.assertIn("\"version\": \"7.14.5\"", meta_content_client)
106+
self.assertIn("\"versions\": {", meta_content_client)
107+
self.assertIn("\"7.14.5\": {\"name\":", meta_content_client)
108+
self.assertIn("\"license\": \"MIT\"", meta_content_client)
109+
self.assertNotIn("\"dist_tags\":", meta_content_client)

0 commit comments

Comments
 (0)