repro-lambda 0.7.2__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- repro_lambda-0.8.0/.release-please-manifest.json +3 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/CHANGELOG.md +11 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/PKG-INFO +2 -2
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/USAGE.md +12 -7
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/pyproject.toml +1 -1
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/__init__.py +1 -1
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/manifest.py +21 -5
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/source_locker.py +51 -6
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_source_locker.py +44 -8
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_sources_schema.py +34 -2
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/uv.lock +1 -1
- repro_lambda-0.7.2/.release-please-manifest.json +0 -3
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.github/workflows/build.yml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.github/workflows/ci.yml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.github/workflows/move-major-tag.yml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.github/workflows/promote.yml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.github/workflows/publish.yml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.github/workflows/release.yml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.gitignore +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/.pre-commit-config.yaml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/LICENSE +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/README.md +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/SETUP.md +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/assets/social-preview.html +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/assets/social-preview.png +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/README.md +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/builds/catalog.json +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/lambdas.toml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/main.tf +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/outputs.tf +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/src/app/app.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/src/app/requirements.arm64.lock +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/variables.tf +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/examples/complete/versions.tf +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/release-please-config.json +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/__main__.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/build.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/catalog.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/cli.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/docker_runner.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/git_guard.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/hasher.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/promote.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/s3_uploader.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/source_stager.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/sources.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/verify.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/src/repro_lambda/zip_packager.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/__init__.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/conftest.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_nodejs_lambda/handler/index.js +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_nodejs_lambda/handler/package-lock.json +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_nodejs_lambda/handler/package.json +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_nodejs_lambda/lambdas.toml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_python_lambda/handler/app.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_python_lambda/handler/requirements.arm64.lock +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_python_lambda/handler/requirements.in +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_python_lambda/lambdas.toml +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_build_integration.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_build_nodejs.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_catalog.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_cli_build.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_cli_lock.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_cli_smoke.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_docker_runner.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_docker_runner_nodejs.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_e2e_nodejs_lambda.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_e2e_python_lambda.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_extra_files.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_git_guard.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_hasher.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_manifest.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_per_lambda_builder.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_promote.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_python_byte_compat_regression.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_s3_uploader.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_source_stager.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_sources.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_sources_hash.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_verify.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_zip_excludes.py +0 -0
- {repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/test_zip_packager.py +0 -0
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.0](https://github.com/antonbabenko/repro-lambda/compare/v0.7.2...v0.8.0) (2026-09-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* **lock:** `version_from` defaults to `format = "mise"`. A manifest that reads a `.tool-versions` file must now declare `format = "asdf"`.
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **lock:** read version_from pins from mise.toml by default ([#15](https://github.com/antonbabenko/repro-lambda/issues/15)) ([a9258af](https://github.com/antonbabenko/repro-lambda/commit/a9258af92fa29227b3c040cc8d7867e8739c3648))
|
|
13
|
+
|
|
3
14
|
## [0.7.2](https://github.com/antonbabenko/repro-lambda/compare/v0.7.1...v0.7.2) (2026-06-23)
|
|
4
15
|
|
|
5
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: repro-lambda
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Build reproducible AWS Lambda packages outside Terraform, optimized for terraform-aws-lambda by serverless.tf.
|
|
5
5
|
Project-URL: Homepage, https://github.com/antonbabenko/repro-lambda
|
|
6
6
|
Project-URL: Repository, https://github.com/antonbabenko/repro-lambda
|
|
@@ -119,7 +119,7 @@ member = "vendor-{version}" # map the versioned top dir to dest
|
|
|
119
119
|
dest = "vendor"
|
|
120
120
|
version = "1.4.0" # bump this one line; lock re-pins everything
|
|
121
121
|
|
|
122
|
-
# A public binary whose version is derived from the vendor release's .
|
|
122
|
+
# A public binary whose version is derived from the vendor release's mise.toml.
|
|
123
123
|
[[lambda.source]]
|
|
124
124
|
name = "terraform"
|
|
125
125
|
type = "https"
|
|
@@ -131,18 +131,23 @@ dest = "bin/terraform"
|
|
|
131
131
|
executable = true
|
|
132
132
|
version = "1.9.0"
|
|
133
133
|
[lambda.source.version_from]
|
|
134
|
-
source = "vendor"
|
|
135
|
-
file = ".
|
|
136
|
-
key = "terraform"
|
|
134
|
+
source = "vendor" # read from the vendor source's extracted tree
|
|
135
|
+
file = "mise.toml" # relative to its member-stripped root
|
|
136
|
+
key = "terraform" # full tool key or its short name
|
|
137
|
+
# format = "asdf" # optional; default "mise"
|
|
137
138
|
```
|
|
138
139
|
|
|
139
140
|
- **Pinning.** `sha256` is verified before the archive is opened. `extract` is
|
|
140
141
|
`zip` / `tar.gz` / `none`. `member` extracts one file or a directory subtree to
|
|
141
142
|
`dest`; omit it to extract the whole archive under `dest`. Source names are
|
|
142
143
|
unique per lambda and dests may not overlap each other or the staged source.
|
|
143
|
-
- **`version_from`** (single-level) derives a source's `version` from
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
- **`version_from`** (single-level) derives a source's `version` from a pin file in
|
|
145
|
+
another source's extracted tree, so bumping the root `version` cascades to
|
|
146
|
+
dependents. It is a lock input - it never affects the artifact hash. `format`
|
|
147
|
+
picks the reader: the default `mise` parses a mise config's `[tools]` table and
|
|
148
|
+
matches `key` against the full tool key or its short name
|
|
149
|
+
(`aqua:hashicorp/terraform` resolves as `terraform`); `asdf` reads a
|
|
150
|
+
`key value` line from a `.tool-versions` file.
|
|
146
151
|
- **`repro-lambda lock`** re-resolves `version_from`, re-downloads, recomputes each
|
|
147
152
|
`sha256`, and rewrites this file (comment-preserving, atomic, idempotent). Run it
|
|
148
153
|
after bumping a `version`. Pass `REPRO_LAMBDA_SOURCES_TOKEN` for private
|
|
@@ -38,6 +38,7 @@ class ExtraFile:
|
|
|
38
38
|
|
|
39
39
|
SUPPORTED_SOURCE_TYPES = {"github_release", "https"}
|
|
40
40
|
SUPPORTED_EXTRACT = {"zip", "tar.gz", "none"}
|
|
41
|
+
SUPPORTED_VERSION_FORMATS = {"mise", "asdf"}
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
@dataclass(frozen=True)
|
|
@@ -45,15 +46,21 @@ class VersionFrom:
|
|
|
45
46
|
"""Lock-time version resolution rule for a source (never hashed).
|
|
46
47
|
|
|
47
48
|
At `lock` time the referenced source (`source`, by name) is fetched + extracted,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
`file` is read from that source's extracted tree, and the version it gives for
|
|
50
|
+
`key` re-pins this source's `version`. `build` never resolves this - it substitutes
|
|
51
|
+
the already-locked `version` into the url/tag/asset templates. Single-level only:
|
|
52
|
+
the referenced source may not itself use version_from.
|
|
53
|
+
|
|
54
|
+
`format` selects the reader. The default `mise` parses a mise config's `[tools]`
|
|
55
|
+
table, matching `key` against either the full tool key or its short name
|
|
56
|
+
("aqua:hashicorp/terraform" -> "terraform"). `asdf` reads a `<key> <value>` line
|
|
57
|
+
from a .tool-versions file.
|
|
52
58
|
"""
|
|
53
59
|
|
|
54
60
|
source: str
|
|
55
61
|
file: str
|
|
56
62
|
key: str
|
|
63
|
+
format: str = "mise"
|
|
57
64
|
|
|
58
65
|
|
|
59
66
|
@dataclass(frozen=True)
|
|
@@ -323,8 +330,17 @@ def _parse_sources(path: Path, entry: dict) -> tuple[Source, ...]:
|
|
|
323
330
|
f"{path}: source {name!r} version_from.source cannot reference itself"
|
|
324
331
|
)
|
|
325
332
|
_validate_relpath(path, "version_from.file", vf_raw["file"], where=f"source {name!r}")
|
|
333
|
+
vf_format = vf_raw.get("format", "mise")
|
|
334
|
+
if vf_format not in SUPPORTED_VERSION_FORMATS:
|
|
335
|
+
raise ValueError(
|
|
336
|
+
f"{path}: source {name!r} version_from.format={vf_format!r} is not one of "
|
|
337
|
+
f"{sorted(SUPPORTED_VERSION_FORMATS)}"
|
|
338
|
+
)
|
|
326
339
|
version_from = VersionFrom(
|
|
327
|
-
source=vf_raw["source"],
|
|
340
|
+
source=vf_raw["source"],
|
|
341
|
+
file=vf_raw["file"],
|
|
342
|
+
key=vf_raw["key"],
|
|
343
|
+
format=vf_format,
|
|
328
344
|
)
|
|
329
345
|
|
|
330
346
|
uses_template = any("{version}" in v for v in (url, tag, asset, member or ""))
|
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
import os
|
|
12
12
|
import tempfile
|
|
13
|
+
import tomllib
|
|
13
14
|
from dataclasses import dataclass, replace
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
|
|
@@ -22,7 +23,7 @@ from repro_lambda.sources import (
|
|
|
22
23
|
extract_to_temp,
|
|
23
24
|
)
|
|
24
25
|
|
|
25
|
-
_MAX_VERSION_FILE_BYTES = 1024 * 1024 #
|
|
26
|
+
_MAX_VERSION_FILE_BYTES = 1024 * 1024 # a pin file is tiny; cap to be safe
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@dataclass
|
|
@@ -35,13 +36,18 @@ class SourcePin:
|
|
|
35
36
|
changed: bool
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
def
|
|
39
|
-
"""Read
|
|
39
|
+
def _read_pin_file(path: Path) -> str:
|
|
40
|
+
"""Read a version_from pin file, with the guards both readers share."""
|
|
40
41
|
if not path.is_file():
|
|
41
42
|
raise SourceFetchError(f"version_from file not found: {path}")
|
|
42
43
|
if path.stat().st_size > _MAX_VERSION_FILE_BYTES:
|
|
43
44
|
raise SourceFetchError(f"version_from file too large: {path}")
|
|
44
|
-
|
|
45
|
+
return path.read_text(encoding="utf-8")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _read_asdf_version(path: Path, key: str) -> str:
|
|
49
|
+
"""Read `<key> <value>` from an asdf-style file (e.g. .tool-versions)."""
|
|
50
|
+
for raw in _read_pin_file(path).splitlines():
|
|
45
51
|
line = raw.strip()
|
|
46
52
|
if not line or line.startswith("#"):
|
|
47
53
|
continue
|
|
@@ -51,6 +57,44 @@ def _read_asdf_version(path: Path, key: str) -> str:
|
|
|
51
57
|
raise SourceFetchError(f"key {key!r} not found in {path.name}")
|
|
52
58
|
|
|
53
59
|
|
|
60
|
+
def _mise_version(spec: object) -> str:
|
|
61
|
+
"""The pinned version of one `[tools]` entry, or "" when it pins none.
|
|
62
|
+
|
|
63
|
+
mise accepts a bare string, a table/inline table with `version`, or a list of
|
|
64
|
+
versions (first wins). An entry with only e.g. `bin_path` pins nothing.
|
|
65
|
+
"""
|
|
66
|
+
if isinstance(spec, str):
|
|
67
|
+
return spec
|
|
68
|
+
if isinstance(spec, dict):
|
|
69
|
+
version = spec.get("version")
|
|
70
|
+
return version if isinstance(version, str) else ""
|
|
71
|
+
if isinstance(spec, list):
|
|
72
|
+
return next((v for v in spec if isinstance(v, str)), "")
|
|
73
|
+
return ""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _read_mise_version(path: Path, key: str) -> str:
|
|
77
|
+
"""Read a tool version from a mise config's `[tools]` table.
|
|
78
|
+
|
|
79
|
+
`key` matches either the full tool key or its short name, so
|
|
80
|
+
"aqua:hashicorp/terraform" and "http:hcledit" both resolve as "terraform"/"hcledit".
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
tools = tomllib.loads(_read_pin_file(path)).get("tools", {})
|
|
84
|
+
except tomllib.TOMLDecodeError as exc:
|
|
85
|
+
raise SourceFetchError(f"version_from file is not valid TOML: {path} ({exc})") from exc
|
|
86
|
+
for raw_key, spec in tools.items():
|
|
87
|
+
if key not in (raw_key, raw_key.split(":", 1)[-1].split("/")[-1]):
|
|
88
|
+
continue
|
|
89
|
+
version = _mise_version(spec)
|
|
90
|
+
if version:
|
|
91
|
+
return version
|
|
92
|
+
raise SourceFetchError(f"key {key!r} not found in {path.name}")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
_VERSION_READERS = {"mise": _read_mise_version, "asdf": _read_asdf_version}
|
|
96
|
+
|
|
97
|
+
|
|
54
98
|
def _ordered(sources: tuple[Source, ...]) -> list[Source]:
|
|
55
99
|
"""Non-version_from sources first (the referenced roots), then dependents.
|
|
56
100
|
|
|
@@ -80,12 +124,13 @@ def _lock_lambda_sources(
|
|
|
80
124
|
f"(it must declare an archive extract)"
|
|
81
125
|
)
|
|
82
126
|
# Read relative to the referenced source's member-stripped tree, so file= can
|
|
83
|
-
# be e.g. ".
|
|
127
|
+
# be e.g. "mise.toml" rather than the version-dependent "pofix-9.9/...".
|
|
84
128
|
base = extracted[ref]
|
|
85
129
|
ref_member = src_by_name[ref].resolved_member
|
|
86
130
|
if ref_member:
|
|
87
131
|
base = base / ref_member
|
|
88
|
-
|
|
132
|
+
read = _VERSION_READERS[src.version_from.format]
|
|
133
|
+
version = read(base / src.version_from.file, src.version_from.key)
|
|
89
134
|
resolved = replace(src, version=version)
|
|
90
135
|
|
|
91
136
|
raw = tmp / f"lock-{src.name}"
|
|
@@ -6,9 +6,12 @@ import tarfile
|
|
|
6
6
|
import zipfile
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
9
11
|
from repro_lambda import source_locker
|
|
10
12
|
from repro_lambda.manifest import load_manifest
|
|
11
13
|
from repro_lambda.source_locker import lock_sources
|
|
14
|
+
from repro_lambda.sources import SourceFetchError
|
|
12
15
|
|
|
13
16
|
OLD_SHA = "0" * 64
|
|
14
17
|
|
|
@@ -29,7 +32,7 @@ def _zip(path: Path, entries: list[tuple[str, bytes]]) -> bytes:
|
|
|
29
32
|
return path.read_bytes()
|
|
30
33
|
|
|
31
34
|
|
|
32
|
-
def _manifest(tmp_path: Path) -> Path:
|
|
35
|
+
def _manifest(tmp_path: Path, pin_file: str = ".tool-versions", pin_format: str = "asdf") -> Path:
|
|
33
36
|
p = tmp_path / "lambdas.toml"
|
|
34
37
|
p.write_text(
|
|
35
38
|
"# keep this comment\n"
|
|
@@ -59,10 +62,11 @@ def _manifest(tmp_path: Path) -> Path:
|
|
|
59
62
|
'extract = "zip"\n'
|
|
60
63
|
'member = "terraform"\n'
|
|
61
64
|
'dest = "bin/terraform"\n'
|
|
62
|
-
'version = "0.0.0"\n' # stale; lock derives it from pofix
|
|
65
|
+
'version = "0.0.0"\n' # stale; lock derives it from the pofix pin file
|
|
63
66
|
"[lambda.source.version_from]\n"
|
|
64
67
|
'source = "pofix"\n'
|
|
65
|
-
'file = "
|
|
68
|
+
f'file = "{pin_file}"\n'
|
|
69
|
+
f'format = "{pin_format}"\n'
|
|
66
70
|
'key = "terraform"\n'
|
|
67
71
|
"\n[builder]\n"
|
|
68
72
|
f'base_image_python = "public.ecr.aws/lambda/python:3.13@sha256:{"0" * 64}"\n'
|
|
@@ -70,11 +74,24 @@ def _manifest(tmp_path: Path) -> Path:
|
|
|
70
74
|
return p
|
|
71
75
|
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
ASDF_PINS = b"terraform 1.9.0\nhcledit 0.2.17\n"
|
|
78
|
+
|
|
79
|
+
# A string pin, a table pin, and an entry that pins no version at all.
|
|
80
|
+
MISE_PINS = b"""[tools]
|
|
81
|
+
"aqua:hashicorp/terraform" = "1.9.0"
|
|
82
|
+
|
|
83
|
+
[tools."http:hcledit"]
|
|
84
|
+
version = "0.2.17"
|
|
85
|
+
|
|
86
|
+
[tools."http:nopin"]
|
|
87
|
+
bin_path = "bin"
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _fixtures(
|
|
92
|
+
tmp_path: Path, pin_name: str = ".tool-versions", pin_body: bytes = ASDF_PINS
|
|
93
|
+
) -> dict[str, bytes]:
|
|
94
|
+
pofix = _targz(tmp_path / "pofix.tgz", [(f"pofix-9.9/{pin_name}", pin_body)])
|
|
78
95
|
tf = _zip(tmp_path / "tf.zip", [("terraform", b"TFBINARY")])
|
|
79
96
|
return {"pofix": pofix, "terraform": tf}
|
|
80
97
|
|
|
@@ -135,3 +152,22 @@ def test_lock_no_sources_returns_false(tmp_path):
|
|
|
135
152
|
f'base_image_python = "public.ecr.aws/lambda/python:3.13@sha256:{"0" * 64}"\n'
|
|
136
153
|
)
|
|
137
154
|
assert lock_sources(p, None) is False
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_lock_resolves_version_from_mise(tmp_path, monkeypatch):
|
|
158
|
+
manifest = _manifest(tmp_path, pin_file="mise.toml", pin_format="mise")
|
|
159
|
+
_install_fake_download(monkeypatch, _fixtures(tmp_path, "mise.toml", MISE_PINS))
|
|
160
|
+
|
|
161
|
+
assert lock_sources(manifest, None) is True
|
|
162
|
+
|
|
163
|
+
by_name = {s.name: s for s in load_manifest(manifest).lambdas[0].sources}
|
|
164
|
+
assert by_name["terraform"].version == "1.9.0" # short name of "aqua:hashicorp/terraform"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_lock_mise_missing_key_raises(tmp_path, monkeypatch):
|
|
168
|
+
manifest = _manifest(tmp_path, pin_file="mise.toml", pin_format="mise")
|
|
169
|
+
pins = MISE_PINS.replace(b'"aqua:hashicorp/terraform" = "1.9.0"', b"")
|
|
170
|
+
_install_fake_download(monkeypatch, _fixtures(tmp_path, "mise.toml", pins))
|
|
171
|
+
|
|
172
|
+
with pytest.raises(SourceFetchError, match="key 'terraform' not found"):
|
|
173
|
+
lock_sources(manifest, None)
|
|
@@ -92,13 +92,45 @@ def test_parse_version_from_and_substitution(tmp_path: Path):
|
|
|
92
92
|
'url="https://releases.example.com/terraform_{version}_linux_arm64.zip"\n'
|
|
93
93
|
f'sha256="{SHA2}"\nextract="zip"\nmember="terraform"\ndest="bin/terraform"\n'
|
|
94
94
|
'version="1.9.0"\n'
|
|
95
|
-
'[lambda.source.version_from]\nsource="pofix"\nfile=".
|
|
95
|
+
'[lambda.source.version_from]\nsource="pofix"\nfile="mise.toml"\nkey="terraform"\n',
|
|
96
96
|
)
|
|
97
97
|
tf = sources[1]
|
|
98
|
-
|
|
98
|
+
# format defaults to mise.
|
|
99
|
+
assert tf.version_from == VersionFrom(source="pofix", file="mise.toml", key="terraform")
|
|
100
|
+
assert tf.version_from.format == "mise"
|
|
99
101
|
assert tf.resolved_url == "https://releases.example.com/terraform_1.9.0_linux_arm64.zip"
|
|
100
102
|
|
|
101
103
|
|
|
104
|
+
def test_version_from_asdf_format_opt_in(tmp_path: Path):
|
|
105
|
+
sources = _load(
|
|
106
|
+
tmp_path,
|
|
107
|
+
"[[lambda.source]]\n"
|
|
108
|
+
'name="pofix"\ntype="github_release"\nrepo="o/pofix"\ntag="pofix-v0.10.0"\n'
|
|
109
|
+
f'asset="pofix-0.10.0.tar.gz"\nsha256="{SHA}"\nextract="tar.gz"\ndest="pofix"\n'
|
|
110
|
+
"[[lambda.source]]\n"
|
|
111
|
+
'name="tf"\ntype="https"\nurl="https://releases.example.com/tf.zip"\n'
|
|
112
|
+
f'sha256="{SHA2}"\nextract="zip"\nmember="terraform"\ndest="bin/terraform"\n'
|
|
113
|
+
"[lambda.source.version_from]\n"
|
|
114
|
+
'source="pofix"\nfile=".tool-versions"\nformat="asdf"\nkey="terraform"\n',
|
|
115
|
+
)
|
|
116
|
+
assert sources[1].version_from.format == "asdf"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_version_from_rejects_unknown_format(tmp_path: Path):
|
|
120
|
+
with pytest.raises(ValueError, match="version_from.format"):
|
|
121
|
+
_load(
|
|
122
|
+
tmp_path,
|
|
123
|
+
"[[lambda.source]]\n"
|
|
124
|
+
'name="pofix"\ntype="github_release"\nrepo="o/pofix"\ntag="pofix-v0.10.0"\n'
|
|
125
|
+
f'asset="pofix-0.10.0.tar.gz"\nsha256="{SHA}"\nextract="tar.gz"\ndest="pofix"\n'
|
|
126
|
+
"[[lambda.source]]\n"
|
|
127
|
+
'name="tf"\ntype="https"\nurl="https://releases.example.com/tf.zip"\n'
|
|
128
|
+
f'sha256="{SHA2}"\nextract="zip"\nmember="terraform"\ndest="bin/terraform"\n'
|
|
129
|
+
"[lambda.source.version_from]\n"
|
|
130
|
+
'source="pofix"\nfile="tool.json"\nformat="json"\nkey="terraform"\n',
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
102
134
|
def test_sources_default_empty(tmp_path: Path):
|
|
103
135
|
assert _load(tmp_path, "") == ()
|
|
104
136
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_nodejs_lambda/handler/index.js
RENAMED
|
File without changes
|
|
File without changes
|
{repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_nodejs_lambda/handler/package.json
RENAMED
|
File without changes
|
|
File without changes
|
{repro_lambda-0.7.2 → repro_lambda-0.8.0}/tests/fixtures/sample_python_lambda/handler/app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|