Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build packages with pinned dependencies from .lock file #3341

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ Note that, at the moment, only pure python wheels are supported.
### Options

* `--format (-f)`: Limit the format to either `wheel` or `sdist`.
* `--lock (-l)`: Add all pinned dependencies from `poetry.lock` to `pyproject.toml` of source and wheels archive

## publish

Expand Down
36 changes: 33 additions & 3 deletions poetry/console/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ class BuildCommand(EnvCommand):
description = "Builds a package, as a tarball and a wheel by default."

options = [
option("format", "f", "Limit the format to either sdist or wheel.", flag=False)
option("format", "f", "Limit the format to either sdist or wheel.", flag=False),
option(
"lock",
"l",
"Add all dependencies as locked dependencies in the distributed pyproject.toml",
flag=True,
),
]

loggers = [
Expand All @@ -19,18 +25,42 @@ class BuildCommand(EnvCommand):
]

def handle(self):
from poetry.core.masonry import Builder
from poetry.core.masonry import builder

fmt = "all"
if self.option("format"):
fmt = self.option("format")

lock = self.option("lock")

package = self.poetry.package
self.line(
"Building <c1>{}</c1> (<c2>{}</c2>)".format(
package.pretty_name, package.version
)
)

builder = Builder(self.poetry)
original_content = self.poetry.file.read()
if lock:
section = "dependencies"

content = self.poetry.file.read()
poetry_content = content["tool"]["poetry"]
if section not in poetry_content:
poetry_content[section] = {}

for dependency_package in self.poetry.locker.lock_data["package"]:
name = dependency_package["name"]
version = dependency_package["version"]
poetry_content[section][name] = version

self._write_pyproject_toml(content)

builder = builder.Builder(self.poetry)
builder.build(fmt, executable=self.env.python)

if lock:
self._write_pyproject_toml(original_content)

def _write_pyproject_toml(self, content):
self.poetry.file.write(content)
83 changes: 83 additions & 0 deletions tests/console/commands/test_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import pytest

from poetry.console.commands.build import BuildCommand
from poetry.core.masonry import builder
from poetry.utils._compat import Path


@pytest.fixture
def source_dir(tmp_path): # type: (Path) -> Path
yield Path(tmp_path.as_posix())


@pytest.fixture
def tester(command_tester_factory):
return command_tester_factory("build")


class MockedBuilder:
def __init__(self, *args, **kw):
pass

def build(self, *args, **kw):
pass


@pytest.fixture
def poetry_with_lock_file(project_factory, fixture_dir):
source = fixture_dir("lock")
pyproject_content = (source / "pyproject.toml").read_text(encoding="utf-8")
poetry_lock_content = (source / "poetry.lock").read_text(encoding="utf-8")
return project_factory(
pyproject_content=pyproject_content, poetry_lock_content=poetry_lock_content,
)


def test_build_without_lock(command_tester_factory, poetry_with_lock_file, monkeypatch):
content_of_written_pyproject_toml = []
monkeypatch.setattr(
BuildCommand,
"_write_pyproject_toml",
lambda _, content: content_of_written_pyproject_toml.append(content),
)
monkeypatch.setattr(builder, "Builder", MockedBuilder)

tester = command_tester_factory("build", poetry=poetry_with_lock_file)
tester.execute()

# pyproject.toml is not changed
assert len(content_of_written_pyproject_toml) == 0


def test_build_with_lock(command_tester_factory, poetry_with_lock_file, monkeypatch):
content_of_written_pyproject_toml = []
monkeypatch.setattr(
BuildCommand,
"_write_pyproject_toml",
lambda _, content: content_of_written_pyproject_toml.append(content),
)
monkeypatch.setattr(builder, "Builder", MockedBuilder)

tester = command_tester_factory("build", poetry=poetry_with_lock_file)
tester.execute("--lock")

assert len(
content_of_written_pyproject_toml[0]["tool"]["poetry"]["dependencies"]
) > len(content_of_written_pyproject_toml[1]["tool"]["poetry"]["dependencies"])
assert content_of_written_pyproject_toml[0]["tool"]["poetry"]["dependencies"] == {
"python": "^3.8",
"sampleproject": ">=1.3.1",
"certifi": "2020.6.20",
"chardet": "3.0.4",
"docker": "4.3.1",
"idna": "2.10",
"pywin32": "227",
"requests": "2.24.0",
"six": "1.15.0",
"urllib3": "1.25.10",
"websocket-client": "0.57.0",
}
assert content_of_written_pyproject_toml[1]["tool"]["poetry"]["dependencies"] == {
"python": "^3.8",
"sampleproject": ">=1.3.1",
}
152 changes: 152 additions & 0 deletions tests/fixtures/lock/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions tests/fixtures/lock/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
authors = ["Poetry Developer <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.8"
sampleproject = ">=1.3.1"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"