shipit-cli 0.11.2__tar.gz → 0.12.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.
Files changed (26) hide show
  1. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/PKG-INFO +1 -1
  2. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/pyproject.toml +4 -1
  3. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/assets/wordpress/install.sh +10 -1
  4. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/cli.py +87 -15
  5. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/generator.py +1 -1
  6. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/base.py +0 -1
  7. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/hugo.py +0 -3
  8. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/laravel.py +0 -3
  9. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/mkdocs.py +1 -4
  10. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/node_static.py +0 -3
  11. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/php.py +0 -3
  12. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/python.py +3 -6
  13. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/staticfile.py +0 -3
  14. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/wordpress.py +2 -5
  15. shipit_cli-0.12.0/src/shipit/version.py +5 -0
  16. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/tests/test_e2e.py +1 -1
  17. shipit_cli-0.11.2/src/shipit/version.py +0 -5
  18. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/.gitignore +0 -0
  19. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/README.md +0 -0
  20. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/__init__.py +0 -0
  21. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/assets/php/php.ini +0 -0
  22. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/assets/wordpress/wp-config.php +0 -0
  23. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/procfile.py +0 -0
  24. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/src/shipit/providers/registry.py +0 -0
  25. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/tests/test_generate_shipit_examples.py +0 -0
  26. {shipit_cli-0.11.2 → shipit_cli-0.12.0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shipit-cli
3
- Version: 0.11.2
3
+ Version: 0.12.0
4
4
  Summary: Shipit CLI is the best way to build, serve and deploy your projects anywhere.
5
5
  Project-URL: homepage, https://wasmer.io
6
6
  Project-URL: repository, https://github.com/wasmerio/shipit
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shipit-cli"
3
- version = "0.11.2"
3
+ version = "0.12.0"
4
4
  description = "Shipit CLI is the best way to build, serve and deploy your projects anywhere."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -45,3 +45,6 @@ dev-dependencies = [
45
45
 
46
46
  [tool.pytest.ini_options]
47
47
  asyncio_mode = "auto"
48
+
49
+ [tool.uv.workspace]
50
+ exclude = ["examples/*"]
@@ -4,7 +4,16 @@ IFS=$'\n\t'
4
4
  export COLUMNS=80 # Prevent WP-CLI from asking for TTY size
5
5
  export PAGER="cat"
6
6
 
7
- alias wp="php /opt/assets/wp-cli.phar --allow-root --path=/app"
7
+ WP_ADMIN_EMAIL=${WP_ADMIN_EMAIL:-"admin@example.com"}
8
+ WP_ADMIN_USERNAME=${WP_ADMIN_USERNAME:-"admin"}
9
+ WP_ADMIN_PASSWORD=${WP_ADMIN_PASSWORD:-"admin"}
10
+ WP_LOCALE=${WP_LOCALE:-"en_US"}
11
+ WP_SITEURL=${WP_SITEURL:-"http://localhost"}
12
+ WP_SITE_TITLE=${WP_SITE_TITLE:-"WordPress"}
13
+
14
+ wp() {
15
+ php /opt/assets/wp-cli.phar --allow-root --path=/app "$@"
16
+ }
8
17
 
9
18
  echo "🚀 Starting WordPress setup..."
10
19
 
@@ -1354,12 +1354,7 @@ class Ctx:
1354
1354
  }
1355
1355
 
1356
1356
 
1357
- def evaluate_shipit(path: Path, builder: Builder) -> Tuple[Ctx, Serve]:
1358
- shipit_file = path / "Shipit"
1359
- if not shipit_file.exists():
1360
- raise FileNotFoundError(
1361
- f"Shipit file not found at {shipit_file}. Run `shipit generate {path}` to create it."
1362
- )
1357
+ def evaluate_shipit(shipit_file: Path, builder: Builder) -> Tuple[Ctx, Serve]:
1363
1358
  source = shipit_file.read_text()
1364
1359
  ctx = Ctx(builder)
1365
1360
  glb = sl.Globals.standard()
@@ -1447,9 +1442,9 @@ def auto(
1447
1442
  None,
1448
1443
  help="Regenerate the Shipit file.",
1449
1444
  ),
1450
- regenerate_path: Optional[Path] = typer.Option(
1445
+ shipit_path: Optional[Path] = typer.Option(
1451
1446
  None,
1452
- help="Regenerate the Shipit file onto the provided path.",
1447
+ help="The path to the Shipit file (defaults to Shipit in the provided path).",
1453
1448
  ),
1454
1449
  wasmer_deploy: Optional[bool] = typer.Option(
1455
1450
  False,
@@ -1499,10 +1494,15 @@ def auto(
1499
1494
  if not path.exists():
1500
1495
  raise Exception(f"The path {path} does not exist")
1501
1496
 
1502
- if not (path / "Shipit").exists() or regenerate or regenerate_path is not None:
1497
+ if not regenerate:
1498
+ if shipit_path and not shipit_path.exists():
1499
+ regenerate = True
1500
+ elif not (path / "Shipit").exists():
1501
+ regenerate = True
1502
+ if regenerate:
1503
1503
  generate(
1504
1504
  path,
1505
- out=regenerate_path,
1505
+ out=shipit_path,
1506
1506
  use_procfile=use_procfile,
1507
1507
  install_command=install_command,
1508
1508
  build_command=build_command,
@@ -1512,6 +1512,7 @@ def auto(
1512
1512
 
1513
1513
  build(
1514
1514
  path,
1515
+ shipit_path=shipit_path,
1515
1516
  wasmer=(wasmer or wasmer_deploy),
1516
1517
  docker=docker,
1517
1518
  docker_client=docker_client,
@@ -1548,6 +1549,9 @@ def generate(
1548
1549
  ),
1549
1550
  out: Optional[Path] = typer.Option(
1550
1551
  None,
1552
+ "-o",
1553
+ "--out",
1554
+ "--output",
1551
1555
  help="Output path (defaults to the Shipit file in the provided path).",
1552
1556
  ),
1553
1557
  use_procfile: bool = typer.Option(
@@ -1610,7 +1614,7 @@ def generate(
1610
1614
  context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
1611
1615
  )
1612
1616
  def _default(ctx: typer.Context) -> None:
1613
- if ctx.invoked_subcommand is None:
1617
+ if ctx.invoked_subcommand in ["auto", "generate", "build", "serve", "deploy", None]:
1614
1618
  print_help()
1615
1619
 
1616
1620
 
@@ -1702,6 +1706,17 @@ def plan(
1702
1706
  help="Project path (defaults to current directory).",
1703
1707
  show_default=False,
1704
1708
  ),
1709
+ out: Optional[Path] = typer.Option(
1710
+ None,
1711
+ "-o",
1712
+ "--out",
1713
+ "--output",
1714
+ help="Output path of the plan (defaults to stdout).",
1715
+ ),
1716
+ shipit_path: Optional[Path] = typer.Option(
1717
+ None,
1718
+ help="The path to the Shipit file (defaults to Shipit in the provided path).",
1719
+ ),
1705
1720
  wasmer: bool = typer.Option(
1706
1721
  False,
1707
1722
  help="Use Wasmer to evaluate the project.",
@@ -1726,10 +1741,41 @@ def plan(
1726
1741
  None,
1727
1742
  help="Use a specific Docker client (such as depot, podman, etc.)",
1728
1743
  ),
1744
+ use_procfile: bool = typer.Option(
1745
+ True,
1746
+ help="Use the Procfile to generate the default custom commands (install, build, start, after_deploy).",
1747
+ ),
1748
+ install_command: Optional[str] = typer.Option(
1749
+ None,
1750
+ help="The install command to use (overwrites the default)",
1751
+ ),
1752
+ build_command: Optional[str] = typer.Option(
1753
+ None,
1754
+ help="The build command to use (overwrites the default)",
1755
+ ),
1756
+ start_command: Optional[str] = typer.Option(
1757
+ None,
1758
+ help="The start command to use (overwrites the default)",
1759
+ ),
1760
+ use_provider: Optional[str] = typer.Option(
1761
+ None,
1762
+ help="Use a specific provider to build the project.",
1763
+ ),
1729
1764
  ) -> None:
1730
1765
  if not path.exists():
1731
1766
  raise Exception(f"The path {path} does not exist")
1732
1767
 
1768
+ if not (path / "Shipit").exists():
1769
+ generate(
1770
+ path,
1771
+ out=None,
1772
+ use_procfile=use_procfile,
1773
+ install_command=install_command,
1774
+ build_command=build_command,
1775
+ start_command=start_command,
1776
+ use_provider=use_provider,
1777
+ )
1778
+
1733
1779
  custom_commands = CustomCommands()
1734
1780
  procfile_path = path / "Procfile"
1735
1781
  if procfile_path.exists():
@@ -1739,6 +1785,8 @@ def plan(
1739
1785
  except Exception:
1740
1786
  pass
1741
1787
 
1788
+ shipit_file = get_shipit_path(path, shipit_path)
1789
+
1742
1790
  builder: Builder
1743
1791
  if docker or docker_client:
1744
1792
  builder = DockerBuilder(path, docker_client)
@@ -1749,7 +1797,7 @@ def plan(
1749
1797
  builder, path, registry=wasmer_registry, token=wasmer_token, bin=wasmer_bin
1750
1798
  )
1751
1799
 
1752
- ctx, serve = evaluate_shipit(path, builder)
1800
+ ctx, serve = evaluate_shipit(shipit_file, builder)
1753
1801
  metadata_commands: Dict[str, Optional[str]] = {
1754
1802
  "start": serve.commands.get("start"),
1755
1803
  "after_deploy": serve.commands.get("after_deploy"),
@@ -1789,7 +1837,14 @@ def plan(
1789
1837
  for svc in (serve.services or [])
1790
1838
  ],
1791
1839
  }
1792
- print(json.dumps(plan_output, indent=4))
1840
+ json_output = json.dumps(plan_output, indent=4)
1841
+ if out:
1842
+ out.parent.mkdir(parents=True, exist_ok=True)
1843
+ out.write_text(json_output)
1844
+ console.print(f"[bold]Plan saved to {out.absolute()}[/bold]")
1845
+ else:
1846
+ sys.stdout.write(json_output+ "\n")
1847
+ sys.stdout.flush()
1793
1848
 
1794
1849
 
1795
1850
  @app.command(name="build")
@@ -1799,6 +1854,10 @@ def build(
1799
1854
  help="Project path (defaults to current directory).",
1800
1855
  show_default=False,
1801
1856
  ),
1857
+ shipit_path: Optional[Path] = typer.Option(
1858
+ None,
1859
+ help="The path to the Shipit file (defaults to Shipit in the provided path).",
1860
+ ),
1802
1861
  wasmer: bool = typer.Option(
1803
1862
  False,
1804
1863
  help="Use Wasmer to build and serve the project.",
@@ -1839,6 +1898,8 @@ def build(
1839
1898
  if not path.exists():
1840
1899
  raise Exception(f"The path {path} does not exist")
1841
1900
 
1901
+ shipit_file = get_shipit_path(path, shipit_path)
1902
+
1842
1903
  builder: Builder
1843
1904
  if docker or docker_client:
1844
1905
  builder = DockerBuilder(path, docker_client)
@@ -1849,7 +1910,7 @@ def build(
1849
1910
  builder, path, registry=wasmer_registry, token=wasmer_token, bin=wasmer_bin
1850
1911
  )
1851
1912
 
1852
- ctx, serve = evaluate_shipit(path, builder)
1913
+ ctx, serve = evaluate_shipit(shipit_file, builder)
1853
1914
  env = {
1854
1915
  "PATH": "",
1855
1916
  "COLORTERM": os.environ.get("COLORTERM", ""),
@@ -1868,6 +1929,7 @@ def build(
1868
1929
  )
1869
1930
  return build(
1870
1931
  path,
1932
+ shipit_path=shipit_path,
1871
1933
  wasmer=wasmer,
1872
1934
  skip_prepare=skip_prepare,
1873
1935
  wasmer_bin=wasmer_bin,
@@ -1898,6 +1960,15 @@ def build(
1898
1960
  builder.prepare(env, serve.prepare)
1899
1961
 
1900
1962
 
1963
+ def get_shipit_path(path: Path, shipit_path: Optional[Path] = None) -> Path:
1964
+ if shipit_path is None:
1965
+ shipit_path = path / "Shipit"
1966
+ if not shipit_path.exists():
1967
+ raise Exception(f"Shipit file not found at {shipit_path}. Run `shipit generate {path}` to create it.")
1968
+ elif not shipit_path.exists():
1969
+ raise Exception(f"Shipit file not found at {shipit_path}. Run `shipit generate {path} -o {shipit_path}` to create it.")
1970
+ return shipit_path
1971
+
1901
1972
  def main() -> None:
1902
1973
  args = sys.argv[1:]
1903
1974
  # If no subcommand or first token looks like option/path → default to "build"
@@ -1909,7 +1980,8 @@ def main() -> None:
1909
1980
  app()
1910
1981
  except Exception as e:
1911
1982
  console.print(f"[bold red]{type(e).__name__}[/bold red]: {e}")
1912
- # raise e
1983
+ if os.environ.get("SHIPIT_DEBUG", "false").lower() in ["1", "true", "yes", "y"]:
1984
+ raise e
1913
1985
 
1914
1986
 
1915
1987
  if __name__ == "__main__":
@@ -95,7 +95,7 @@ def generate_shipit(path: Path, custom_commands: CustomCommands, use_provider: O
95
95
  # Collect parts
96
96
  plan = ProviderPlan(
97
97
  serve_name=provider.serve_name(),
98
- provider=provider.provider_kind(),
98
+ provider=provider.name(),
99
99
  platform=provider.platform(),
100
100
  mounts=provider.mounts(),
101
101
  volumes=provider.volumes(),
@@ -28,7 +28,6 @@ class Provider(Protocol):
28
28
  def initialize(self) -> None: ...
29
29
  # Structured plan steps (no path args; use self.path)
30
30
  def serve_name(self) -> str: ...
31
- def provider_kind(self) -> str: ...
32
31
  def platform(self) -> Optional[str]: ...
33
32
  def dependencies(self) -> list["DependencySpec"]: ...
34
33
  def declarations(self) -> Optional[str]: ...
@@ -27,9 +27,6 @@ class HugoProvider(StaticFileProvider):
27
27
  def serve_name(self) -> str:
28
28
  return self.path.name
29
29
 
30
- def provider_kind(self) -> str:
31
- return "staticsite"
32
-
33
30
  def platform(self) -> Optional[str]:
34
31
  return "hugo"
35
32
 
@@ -36,9 +36,6 @@ class LaravelProvider:
36
36
  def serve_name(self) -> str:
37
37
  return self.path.name
38
38
 
39
- def provider_kind(self) -> str:
40
- return "php"
41
-
42
39
  def platform(self) -> Optional[str]:
43
40
  return "laravel"
44
41
 
@@ -40,11 +40,8 @@ class MkdocsProvider(StaticFileProvider):
40
40
  def serve_name(self) -> str:
41
41
  return self.path.name
42
42
 
43
- def provider_kind(self) -> str:
44
- return "mkdocs-site"
45
-
46
43
  def platform(self) -> Optional[str]:
47
- return "mkdocs"
44
+ return None
48
45
 
49
46
  def dependencies(self) -> list[DependencySpec]:
50
47
  return [
@@ -231,9 +231,6 @@ class NodeStaticProvider(StaticFileProvider):
231
231
  def serve_name(self) -> str:
232
232
  return self.path.name
233
233
 
234
- def provider_kind(self) -> str:
235
- return "staticsite"
236
-
237
234
  def platform(self) -> Optional[str]:
238
235
  return self.static_generator.value if self.static_generator else None
239
236
 
@@ -52,9 +52,6 @@ class PhpProvider:
52
52
  def serve_name(self) -> str:
53
53
  return self.path.name
54
54
 
55
- def provider_kind(self) -> str:
56
- return "php"
57
-
58
55
  def platform(self) -> Optional[str]:
59
56
  return None
60
57
 
@@ -226,9 +226,6 @@ class PythonProvider:
226
226
  def serve_name(self) -> str:
227
227
  return self.path.name
228
228
 
229
- def provider_kind(self) -> str:
230
- return "python"
231
-
232
229
  def platform(self) -> Optional[str]:
233
230
  return self.framework.value if self.framework else None
234
231
 
@@ -327,8 +324,8 @@ class PythonProvider:
327
324
  elif has_requirements or extra_deps:
328
325
  steps += [
329
326
  'env(UV_PROJECT_ENVIRONMENT=local_venv["build"] if cross_platform else venv["build"])',
330
- 'run(f"uv init --no-workspace", inputs=[], outputs=["uv.lock"], group="install")',
331
- 'copy(".", ".")' if self.install_requires_all_files else None,
327
+ 'run(f"uv init", inputs=[], outputs=["uv.lock"], group="install")',
328
+ 'copy(".", ".", ignore=[".venv", ".git", "__pycache__"])' if self.install_requires_all_files else None,
332
329
  ]
333
330
  if has_requirements:
334
331
  steps += [
@@ -347,7 +344,7 @@ class PythonProvider:
347
344
 
348
345
  steps += [
349
346
  'path((local_venv["build"] if cross_platform else venv["build"]) + "/bin")',
350
- 'copy(".", ".", ignore=[".venv", ".git", "__pycache__"])',
347
+ 'copy(".", ".", ignore=[".venv", ".git", "__pycache__"])' if not self.install_requires_all_files else None,
351
348
  ]
352
349
  if self.framework == PythonFramework.MCP:
353
350
  steps += [
@@ -58,9 +58,6 @@ class StaticFileProvider:
58
58
  def serve_name(self) -> str:
59
59
  return self.path.name
60
60
 
61
- def provider_kind(self) -> str:
62
- return "staticfile"
63
-
64
61
  def platform(self) -> Optional[str]:
65
62
  return None
66
63
 
@@ -43,11 +43,8 @@ class WordPressProvider(PhpProvider):
43
43
  def serve_name(self) -> str:
44
44
  return self.path.name
45
45
 
46
- def provider_kind(self) -> str:
47
- return "php"
48
-
49
46
  def platform(self) -> Optional[str]:
50
- return "wordpress"
47
+ return None
51
48
 
52
49
  def dependencies(self) -> list[DependencySpec]:
53
50
  return [
@@ -81,7 +78,7 @@ class WordPressProvider(PhpProvider):
81
78
  def commands(self) -> Dict[str, str]:
82
79
  commands = super().commands()
83
80
  return {
84
- "wp": '"php {}/wp-cli.phar --allow-root --path={}".format(assets["serve"], app["serve"])',
81
+ # "wp": '"php {}/wp-cli.phar --allow-root --path={}".format(assets["serve"], app["serve"])',
85
82
  "after_deploy": '"bash {}/setup-wp.sh".format(assets["serve"])',
86
83
  **commands,
87
84
  }
@@ -0,0 +1,5 @@
1
+ __all__ = ["version", "version_info"]
2
+
3
+
4
+ version = "0.12.0"
5
+ version_info = (0, 12, 0, "final", 0)
@@ -165,7 +165,7 @@ class E2ECase(NamedTuple):
165
165
  ],
166
166
  ids=lambda c: str(c),
167
167
  )
168
- @pytest.mark.flaky(reruns=5, reruns_delay=2)
168
+ @pytest.mark.flaky(reruns=2, reruns_delay=2)
169
169
  @pytest.mark.parametrize(
170
170
  "build_mode",
171
171
  [
@@ -1,5 +0,0 @@
1
- __all__ = ["version", "version_info"]
2
-
3
-
4
- version = "0.11.2"
5
- version_info = (0, 11, 2, "final", 0)
File without changes
File without changes